<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <meta name="referrer" content="never" />
  
  
  <meta name="description" content="写在前面，本人也是一个每天做一个正确的决定，from now on。
前言自己学Java总是觉得迷迷糊糊的，感觉自己啥都不会，但是自己学了三年Java又感觉自己啥都会点，但是又感觉自己学的东西已经过时了，如果你跟我一样，那么这篇文章会非常适合你，我会不定时更新我的最新学习动态。欢迎大家start me。
本片Java主要是以Java8为主，捎带其他版本的Java。

 PS.本人参考的是多方面的资料来源，在文中会尽可能标注来源出处，如有地方忘记标注，或感觉本人未标注的可以联系本人。" />
  

  
  
  <meta name="google-site-verification" content="NCXVSqxqB-os803-VFMtIEd1SUNJVOIjctCfNYUwD0w" />
  <meta name="baidu-site-verification" content="Nzwx7HuplM" />
  
  <meta name="msvalidate.01" content="9E9EA92F7E5327E1FE8A5196D5253664" />
  
  
  
  <title>Java | masuo777的博客</title>
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
  <meta name="description" content="写在前面，本人也是一个每天做一个正确的决定，from now on。 前言自己学Java总是觉得迷迷糊糊的，感觉自己啥都不会，但是自己学了三年Java又感觉自己啥都会点，但是又感觉自己学的东西已经过时了，如果你跟我一样，那么这篇文章会非常适合你，我会不定时更新我的最新学习动态。欢迎大家start me。 本片Java主要是以Java8为主，捎带其他版本的Java。   PS.本人参考的是多方面的资">
<meta property="og:type" content="article">
<meta property="og:title" content="Java">
<meta property="og:url" content="https://masuo777.github.io/2021/08/01/java/index.html">
<meta property="og:site_name" content="masuo777的博客">
<meta property="og:description" content="写在前面，本人也是一个每天做一个正确的决定，from now on。 前言自己学Java总是觉得迷迷糊糊的，感觉自己啥都不会，但是自己学了三年Java又感觉自己啥都会点，但是又感觉自己学的东西已经过时了，如果你跟我一样，那么这篇文章会非常适合你，我会不定时更新我的最新学习动态。欢迎大家start me。 本片Java主要是以Java8为主，捎带其他版本的Java。   PS.本人参考的是多方面的资">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://masuo-github-image.oss-cn-beijing.aliyuncs.com/image/Javapath2021.jpg">
<meta property="og:image" content="https://masuo-github-image.oss-cn-beijing.aliyuncs.com/image/20210704175724.png">
<meta property="og:image" content="https://masuo-github-image.oss-cn-beijing.aliyuncs.com/image/20210708235745.png">
<meta property="og:image" content="https://masuo-github-image.oss-cn-beijing.aliyuncs.com/image/20210710200444.png">
<meta property="og:image" content="https://masuo-github-image.oss-cn-beijing.aliyuncs.com/image/20210717224314.jpg">
<meta property="og:image" content="https://masuo-github-image.oss-cn-beijing.aliyuncs.com/image/20210726144113.png">
<meta property="og:image" content="https://masuo-github-image.oss-cn-beijing.aliyuncs.com/image/20210722193012.png">
<meta property="og:image" content="https://masuo-github-image.oss-cn-beijing.aliyuncs.com/image/20210726113913.png">
<meta property="og:image" content="https://masuo-github-image.oss-cn-beijing.aliyuncs.com/image/20210726154140.png">
<meta property="og:image" content="https://masuo-github-image.oss-cn-beijing.aliyuncs.com/image/20210726154521.png">
<meta property="og:image" content="https://masuo-github-image.oss-cn-beijing.aliyuncs.com/image/20210717210858.png">
<meta property="og:image" content="https://masuo-github-image.oss-cn-beijing.aliyuncs.com/image/20211221170028.webp">
<meta property="og:image" content="https://masuo-github-image.oss-cn-beijing.aliyuncs.com/image/20211222102906.png">
<meta property="og:image" content="https://masuo-github-image.oss-cn-beijing.aliyuncs.com/image/20211221174013.png">
<meta property="og:image" content="https://masuo-github-image.oss-cn-beijing.aliyuncs.com/image/Java%20IO.png">
<meta property="og:image" content="https://masuo-github-image.oss-cn-beijing.aliyuncs.com/image/20211221170413.webp">
<meta property="og:image" content="https://pic3.zhimg.com/v2-dfc3b65b983a82e84420e1335a507e2a_r.jpg">
<meta property="article:published_time" content="2021-08-01T00:00:00.000Z">
<meta property="article:modified_time" content="2022-04-20T06:19:21.001Z">
<meta property="article:author" content="John Doe">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://masuo-github-image.oss-cn-beijing.aliyuncs.com/image/Javapath2021.jpg">
  
    <link rel="alternative" href="/atom.xml" title="masuo777的博客" type="application/atom+xml">
  
  
    <link rel="icon" href="http://7u2hdm.com1.z0.glb.clouddn.com/favicon.ico">
  
  
<link rel="stylesheet" href="/css/style.css">

  

  
  <!-- baidu webmaster push -->
  <script src='//push.zhanzhang.baidu.com/push.js'></script>
<meta name="generator" content="Hexo 5.4.0"></head>
<body class="home blog custom-background custom-font-enabled single-author">
  <div id="page" class="hfeed site">
      <header id="masthead" class="site-header" role="banner">
    <hgroup>
      <h1 class="site-title">
        <a href="/" title="masuo777的博客" rel="home">masuo777的博客</a>
      </h1>
      
        <script type="text/javascript" src="http://api.hitokoto.us/rand?encode=js&charset=utf-8"></script>
        <h2 class="site-description"><script>hitokoto();</script></h2>
      
    </hgroup>

    <nav id="site-navigation" class="main-navigation" role="navigation">
            <button class="menu-toggle">菜单</button>
            <a class="assistive-text" href="/#content" title="跳至内容">跳至内容</a><!--TODO-->
            <div class="menu-main-container">
                <ul id="menu-main" class="nav-menu">
                
                    <li class="menu-item menu-item-type-post_type menu-item-object-page"><a href="/">MDS</a></li>
                
                    <li class="menu-item menu-item-type-post_type menu-item-object-page"><a href="/todo">ToDo</a></li>
                
                    <li class="menu-item menu-item-type-post_type menu-item-object-page"><a href="/images">images</a></li>
                
                    <li class="menu-item menu-item-type-post_type menu-item-object-page"><a href="/about">ME</a></li>
                
                    <li class="menu-item menu-item-type-post_type menu-item-object-page"><a href="/works">作品集</a></li>
                
                    <li class="menu-item menu-item-type-post_type menu-item-object-page"><a href="/tools">工具集</a></li>
                
                    <li class="menu-item menu-item-type-post_type menu-item-object-page"><a target="_blank" rel="noopener" href="https://github.com/Masuo777">my github</a></li>
                
                </ul>
            </div>
    </nav>
</header>
      <div id="main" class="wrapper">
        <div id="primary" class="site-content"><div id="content" role="main"><article id="post-java" class="post-java post type-post status-publish format-standard hentry">
    <!---->

      <header class="entry-header">
        
        
  
    <h1 class="entry-title article-title">
      Java
    </h1>
  

        
        <div class="comments-link">
            
            <a href="/2021/08/01/java/#comments" class="leave-reply">评论</a>
            
            <a href="javascript:void(0);" data-url="https://masuo777.github.io/2021/08/01/java/" data-id="cl3jit8nr000i2ojb2hxj7ypp" class="leave-reply bdsharebuttonbox" data-cmd="more">分享</a>
        </div><!-- .comments-link -->
      </header><!-- .entry-header -->

    <div class="entry-content">
      
        <p>写在前面，本人也是一个<br>每天做一个正确的决定，from now on。</p>
<h4 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h4><p>自己学Java总是觉得迷迷糊糊的，感觉自己啥都不会，但是自己学了三年Java又感觉自己啥都会点，但是又感觉自己学的东西已经过时了，如果你跟我一样，那么这篇文章会非常适合你，我会不定时更新我的最新学习动态。欢迎大家start me。</p>
<p>本片Java主要是以Java8为主，捎带其他版本的Java。</p>
<blockquote>
<p> PS.本人参考的是多方面的资料来源，在文中会尽可能标注来源出处，如有地方忘记标注，或感觉本人未标注的可以联系本人。</p>
</blockquote>
<span id="more"></span>

<p>先来看一下，Java学习路线指南。</p>
<h5 id="2021威哥版-直通阿里P7技术栈"><a href="#2021威哥版-直通阿里P7技术栈" class="headerlink" title="2021威哥版-直通阿里P7技术栈"></a>2021威哥版-直通阿里P7技术栈</h5><p><img src="https://masuo-github-image.oss-cn-beijing.aliyuncs.com/image/Javapath2021.jpg" alt="img"></p>
<p>图来源：<a target="_blank" rel="noopener" href="https://zhuanlan.zhihu.com/p/360820993">https://zhuanlan.zhihu.com/p/360820993</a></p>
<p><img src="https://masuo-github-image.oss-cn-beijing.aliyuncs.com/image/20210704175724.png" alt="image-20210704175723111"></p>
<p>图来自二哥的gitee仓库：<a target="_blank" rel="noopener" href="https://gitee.com/itwanger/JavaBooks#https://pan.baidu.com/s/1rT0l5ynzAQLF--efyRHzQw%EF%BC%8C%E4%B9%8B%E6%89%80%E4%BB%A5%E9%80%89gitee%E4%BB%93%E5%BA%93%E6%98%AF%E5%9B%A0%E4%B8%BA%EF%BC%8C%E8%BF%99%E4%B8%AA%E5%BF%AB%E3%80%82">https://gitee.com/itwanger/JavaBooks#https://pan.baidu.com/s/1rT0l5ynzAQLF--efyRHzQw，之所以选gitee仓库是因为，这个快。</a></p>
<p>本文的学习路线不会完全按照上述图片。</p>
<h1 id="Java基础技术"><a href="#Java基础技术" class="headerlink" title="Java基础技术"></a>Java基础技术</h1><p>Java最核心的一直将是Java基础，不论你的框架如何，Java的基础才是建立起实用的框架的核心。</p>
<h2 id="Java概述"><a href="#Java概述" class="headerlink" title="Java概述"></a>Java概述</h2><p>首先，来重新过一遍自己学习Java最开始那一段快乐的时光，以及自己没来得及了解的我们所不太了解的Java，这一次让我们一起揭开Java的神秘面纱。</p>
<h3 id="什么是Java？"><a href="#什么是Java？" class="headerlink" title="什么是Java？"></a>什么是Java？</h3><p>Java是<strong>sun</strong>公司在1995年发布的编程语言和计算平台。Java作为编程语言是我们众所周知的，那么作为计算平台的Java语言你了解多少呢。</p>
<p>想想Java与其他语言有啥区别：Java开发是<strong>跨平台</strong>的。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">计算平台是计算机系统硬件与软件的设计和开发的基础。具有一定的标准性和公开性，同时也决定了该计算机系统的硬件与软件的性能。了解即可。</span><br></pre></td></tr></table></figure>

<p>Java主要分为三个版本：</p>
<p>J2SE：Java2 Platform Standard Edition，java平台标准版，支持在大多数环境下适用Java应用程序，为以下两位提供基础服务。</p>
<p>J2EE：Java2 platform Enterprise Edition，Java平台企业版，企业版，强大，完整，健壮。</p>
<p>J2ME：Java2 platform Micro Edition，Java平台微型版，主要为微型机器及嵌入式设备提供运行环境。</p>
<p>我们经常用的是SE版本，也可以用到EE，看个人需求。</p>
<h3 id="Java的特点"><a href="#Java的特点" class="headerlink" title="Java的特点"></a>Java的特点</h3><ul>
<li><strong>面向对象</strong>，这里来复习一下面向对象与面向过程开发的区别。</li>
</ul>
<p>首先有的是面向过程开发，以过程为中心，解决一个问题需要哪些过程，针对过程去开发，比如1+1，首先输入第一个数字，然后输入运算符，然后输入第二个运算符，最后计算结果，然后输出结果，代表语言是C。</p>
<p>其次是面向对象开发，简称OOP，面向对象是以对象为中心，代表语言是C++，Java。</p>
<p>这两个开发方式的区别具体可以参考：<a target="_blank" rel="noopener" href="https://www.zhihu.com/question/27468564/answer/757537214">https://www.zhihu.com/question/27468564/answer/757537214</a></p>
<p>这个作者解释的生动形象，而且非常容易理解，还提供了面试见解。</p>
<ul>
<li><strong>无指针</strong>，不用手动管理对象的生命周期，指针一直是c语言中最难的那部分，也是最为劝退新手的部分，在Java中完全不用担心指针的问题。</li>
<li><strong>静态语言开发</strong>，静态语言主要有Pascal, Perl, C/C++, JAVA, C#, Scala等</li>
<li><strong>跨平台性</strong>，这是Java最受欢迎的原因了吧，Java的跨平台性，让他在多个操作系统中畅通无阻的执行，而实现Java跨平台的原因就是jvm，这也是Java最核心的部分。</li>
</ul>
<h3 id="Java开发环境"><a href="#Java开发环境" class="headerlink" title="Java开发环境"></a>Java开发环境</h3><h4 id="JDK"><a href="#JDK" class="headerlink" title="JDK"></a>JDK</h4><p>包含Java的运行环境以及开发环境。适合开发人员开发时使用。</p>
<h4 id="JRE"><a href="#JRE" class="headerlink" title="JRE"></a>JRE</h4><p>只包括Java的运行环境,以及部分Java的基础库。适合在项目完成之后，搭建项目时使用。</p>
<p>接下来进入正题。</p>
<h2 id="数据类型"><a href="#数据类型" class="headerlink" title="数据类型"></a>数据类型</h2><h3 id="基本类型"><a href="#基本类型" class="headerlink" title="基本类型"></a>基本类型</h3><p>Java有8种基本类型，分为整形(短整型，整型，长整型)，浮点型（double,float），布尔类型(boolean)，字符型(byte,char)</p>
<ul>
<li>byte/8位</li>
<li>char/16位</li>
<li>short/16</li>
<li>int/32</li>
<li>float/32</li>
<li>double/63</li>
<li>long/64</li>
<li>boolean/</li>
</ul>
<p>boolean只有两个值，true/false，没有明确的大小，jvm在编译时期为了方便，将Boolean转成int类型，因为1bit没有独立地址，而int有（byte也有）。</p>
<h3 id="包装类型（封装类）"><a href="#包装类型（封装类）" class="headerlink" title="包装类型（封装类）"></a>包装类型（封装类）</h3><p>每个基础类型都会对应一个封装类，基础类型与其对应的包装类型之间的赋值使用自动装箱与拆箱完成。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Integer i = <span class="number">2</span>;<span class="comment">//装箱，将基础类封装起来，叫装箱。调用了Integer.valueOf(2)</span></span><br><span class="line"><span class="keyword">int</span> j = i;<span class="comment">//拆箱,与之对应的就是拆箱。调用了X.intValue()</span></span><br></pre></td></tr></table></figure>

<h4 id="缓存池"><a href="#缓存池" class="headerlink" title="缓存池"></a>缓存池</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">new</span> Integer(<span class="number">123</span>)</span><br><span class="line">Integer.valueOf(<span class="number">123</span>)</span><br><span class="line">   <span class="comment">//看看这两个声明类型的区别</span></span><br></pre></td></tr></table></figure>

<p>以上两者的区别在于：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//new Integer(123)每次都会创建一个新的对象</span></span><br><span class="line"><span class="comment">//Integer.valueOf(123)会使用缓冲池中的对象，对此调用会取得同一个对象的引用</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//实例</span></span><br><span class="line">Integer x = <span class="keyword">new</span> Integer(<span class="number">123</span>);</span><br><span class="line">Integer y = <span class="keyword">new</span> Integer(<span class="number">123</span>);</span><br><span class="line">System.out.println(x==y);<span class="comment">//false</span></span><br><span class="line"></span><br><span class="line">Integer i = Integer.valueOf(<span class="number">123</span>);</span><br><span class="line">Integer j = Integer.valueOf(<span class="number">123</span>);</span><br><span class="line">System.out.println(i==j);<span class="comment">//true</span></span><br></pre></td></tr></table></figure>

<p>基本类型对应的缓存池如下：</p>
<ul>
<li>boolean ：true/false</li>
<li>byte ：all bytes</li>
<li>short/int : -128 ~127</li>
<li>char : \u0000(第0个) ~ \u007F（第127个）</li>
</ul>
<h2 id="字符串String"><a href="#字符串String" class="headerlink" title="字符串String"></a>字符串String</h2><h3 id="概览"><a href="#概览" class="headerlink" title="概览"></a>概览</h3><p>String被升为final，因此String是不可继承的（包括其他封装类）。</p>
<p>在Java8中，String使用char数组存储数据。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">final</span> <span class="class"><span class="keyword">class</span> <span class="title">String</span></span></span><br><span class="line"><span class="class"> 	<span class="keyword">implements</span> <span class="title">java</span>.<span class="title">io</span>.<span class="title">Serializable</span>, <span class="title">Comparable</span>&lt;<span class="title">String</span>&gt;, <span class="title">CharSequence</span> </span>&#123;</span><br><span class="line"> <span class="comment">/** The value is used for character storage. */</span></span><br><span class="line"> 	<span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">char</span> value[];</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<p>在Java9中，String使用byte数组存储数据,同时使用coder来标识使用了那种编码。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">final</span> <span class="class"><span class="keyword">class</span> <span class="title">String</span></span></span><br><span class="line"><span class="class"> <span class="keyword">implements</span> <span class="title">java</span>.<span class="title">io</span>.<span class="title">Serializable</span>, <span class="title">Comparable</span>&lt;<span class="title">String</span>&gt;, <span class="title">CharSequence</span> </span>&#123;</span><br><span class="line"> <span class="comment">/** The value is used for character storage. */</span></span><br><span class="line"> 	<span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">byte</span>[] value;</span><br><span class="line"> <span class="comment">/** The identifier of the encoding used to encode the bytes in &#123;<span class="doctag">@code</span></span></span><br><span class="line"><span class="comment">value&#125;. */</span></span><br><span class="line"> 	<span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">byte</span> coder;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>在以上源码中可以看到String的char/byte数组都被声明为了final，所以意味着数组在声明之后就是不能变得，也就是说String声明后是不可变的。</p>
<p>声明为final的优点：</p>
<ul>
<li>缓存hash值，</li>
</ul>
<p>因为String的hash值经常被调用，如hash map中的key值经常是String，String的不可变性，使得hash值也不会变，因此只需一次计算。</p>
<ul>
<li>String Pool的需要</li>
</ul>
<p>如果一个String被创建过了，那么就会从String pool 中取得引用，只有String是不可变的，才能使用String pool。</p>
<ul>
<li>安全性</li>
</ul>
<p>String 经常作为参数，String 不可变性可以保证参数不可变。例如在作为⽹络连接参数的情况下如果 String 是可变的，那么在⽹络连接过程中，String 被改变，改变 String 的那⼀⽅以为现在连接的是其它 主机，⽽实际情况却不⼀定是</p>
<ul>
<li>线程安全</li>
</ul>
<p>在多个线程中String值仍保持不变，使得在线程中可以安全的使用String。</p>
<h3 id="String-，String-buffer-，String-Builder"><a href="#String-，String-buffer-，String-Builder" class="headerlink" title="String ，String buffer ，String Builder"></a>String ，String buffer ，String Builder</h3><ul>
<li>可变性</li>
</ul>
<p>String 不可变，String buffer和String builder可变</p>
<ul>
<li>线程安全（security）</li>
</ul>
<p>String不可变，所以是线程安全的，</p>
<p>String buffer是线程不安全的</p>
<p>String builder是线程安全的，内部使用synchronized(锁)同步</p>
<h3 id="String-pool"><a href="#String-pool" class="headerlink" title="String pool"></a>String pool</h3><p>与缓存池功能类似，用来保存着所有字符串字面量，这些字面量在编译时期就确定了。不仅如此，还可以使用String的intern()方法在运行过程将字符串添加到String pool。</p>
<p>这里引入了一个<strong>字符串字面量</strong>的定义：字符串字面量即指声明的String类型双引号之间的常量，如“stir”中的stir。</p>
<p>当一个字符串调用intern()方法时，如果String pool中已经存在一个字符串和该字符串值相等（值相等要用.equals()来判断），那么就会返回String pool中字符串的引用；否则，就会在String pool中添加一个新的字符串，并返回这个字符串的引用。</p>
<p>使用new新建字符串是不同的两个字符串，使用intern()方法创建的对象是对同一个字符串的引用。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">String s1 = <span class="keyword">new</span> String(<span class="string">&quot;123&quot;</span>);</span><br><span class="line">String s2 = <span class="keyword">new</span> String(<span class="string">&quot;123&quot;</span>);</span><br><span class="line">System.out.println(s1==s2);<span class="comment">//false</span></span><br><span class="line">String s3 = s1.intern();</span><br><span class="line">String s4 = s2.intern();</span><br><span class="line">System.out.println(s3==s4);<span class="comment">//true</span></span><br></pre></td></tr></table></figure>

<p>使用赋值的方式创建对象时，都是从String pool中引用对象，所以他们都是相等的。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">String s5 = <span class="string">&quot;555&quot;</span>;</span><br><span class="line">String s6 = <span class="string">&quot;555&quot;</span>;</span><br><span class="line">System.out.println(s5==s6);<span class="comment">//true</span></span><br></pre></td></tr></table></figure>

<p>在Java7之前，String pool存放在运行时常量池中，他属于永久代，而在Java7之后，将String pool移到了堆中，这是因为永久代的空间有限，在大量使用字符串的场景下会报Out of memory的错误。</p>
<h4 id="注意："><a href="#注意：" class="headerlink" title="注意："></a>注意：</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//使用new 新建字符串会新建两个字符串（前提是String pool中不存在与新建变量值相等的对象），</span></span><br></pre></td></tr></table></figure>

<h3 id="Java-new一个对象的过程"><a href="#Java-new一个对象的过程" class="headerlink" title="Java new一个对象的过程"></a>Java new一个对象的过程</h3><p>参考：<a target="_blank" rel="noopener" href="https://zhuanlan.zhihu.com/p/339839277">https://zhuanlan.zhihu.com/p/339839277</a> ，这是个人觉的还算能看懂的一篇。</p>
<p>一看到new这个关键字，我们脑海里应该是，他在Java的堆内存中开辟了一块空间。</p>
<p>过程过于复杂，简单来说，就是以下几个步骤，</p>
<ol>
<li>当虚拟机收到一条new指令时，首先检查这个指令的参数能否在常量池中定位到一个类的符号引用，然后检查这个类是否被加载解析，初始化，即验证是否第一次使用这个类，如果不是第一次使用则需要先执行对应类的加载过程，</li>
</ol>
<h3 id="声明"><a href="#声明" class="headerlink" title="声明"></a>声明</h3><p>String 变量名 = 变量值；双引号</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">String s = “string”;</span><br></pre></td></tr></table></figure>

<h3 id="charAt用法"><a href="#charAt用法" class="headerlink" title="charAt用法"></a>charAt用法</h3><p>charAt是根据下表取出字符串中对应的字符的一种方法：<strong>字符串名称.charAt(字符下标)</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">String s = <span class="string">&quot;String&quot;</span>;</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>;i&lt;=<span class="number">5</span>;i++)&#123;</span><br><span class="line">    System.out.println(s.charAt(i));</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//输出：S t r i n </span></span><br></pre></td></tr></table></figure>

<h3 id="在字符串后面加字符串或字符"><a href="#在字符串后面加字符串或字符" class="headerlink" title="在字符串后面加字符串或字符"></a>在字符串后面加字符串或字符</h3><p>使用‘+=’即可，string1+=string2/</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">String s1=<span class="string">&quot;aaa&quot;</span>;</span><br><span class="line">String s2=<span class="string">&quot;bbb&quot;</span>;</span><br><span class="line">String s3=s1+s2;</span><br><span class="line"><span class="comment">//s3=&quot;aaabbb&quot;</span></span><br></pre></td></tr></table></figure>

<h3 id="foreach的使用"><a href="#foreach的使用" class="headerlink" title="foreach的使用"></a>foreach的使用</h3><p>只能针对数组类型的变量进行遍历输出等操作：<strong>for(类型 变量名：数组名)</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">String []arr = &#123;<span class="string">&quot;aaadd&quot;</span>,<span class="string">&quot;aaasss&quot;</span>,<span class="string">&quot;aaaaaa&quot;</span>&#125;;</span><br><span class="line"><span class="keyword">for</span>(String s:arr)&#123;</span><br><span class="line">    System.out.println(s);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//输出：aaadd aaasss aaaaaa</span></span><br></pre></td></tr></table></figure>



<h2 id="运算"><a href="#运算" class="headerlink" title="运算"></a>运算</h2><h3 id="参数传递"><a href="#参数传递" class="headerlink" title="参数传递"></a>参数传递</h3><p>在Java中，参数是以值传递的方式传入方法中，而不是引用传递。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> JavaBase;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> masuo</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@create</span> 2021/7/8 23:01</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Description</span> java中的参数传递 是值传递</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ParmeterPass</span> </span>&#123;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="comment">// 此时的dog是一个指针，存储对象的地址，</span></span><br><span class="line">        <span class="comment">// 在将一个参数传入一个方法时，本质上是将对象的地址以值的方式传递到形参中。</span></span><br><span class="line">        Dog doga = <span class="keyword">new</span> Dog(<span class="string">&quot;doga&quot;</span>);</span><br><span class="line">        changeDogName(doga);</span><br><span class="line">        System.out.println(doga.getName());<span class="comment">//dogb</span></span><br><span class="line"></span><br><span class="line">        System.out.println(doga.getAddress());<span class="comment">//JavaBase.Dog@1b6d3586</span></span><br><span class="line">        changeDogAddress(doga);</span><br><span class="line">        System.out.println(doga.getName());<span class="comment">//dogb，这里名称没变是因为方法中的对象对此处无影响，因为没有返回赋值的操作</span></span><br><span class="line">        System.out.println(doga.getAddress());<span class="comment">//JavaBase.Dog@1b6d3586，与上面相同，在方法中改变对象，对此处无影响</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">changeDogAddress</span><span class="params">(Dog doga)</span> </span>&#123;</span><br><span class="line">        System.out.println(doga.getAddress());<span class="comment">//JavaBase.Dog@1b6d3586,在这里还与上面的地址相同，因为地址还没发生改变</span></span><br><span class="line">        doga = <span class="keyword">new</span> Dog(<span class="string">&quot;dogc&quot;</span>);<span class="comment">//生成新的dog对象，</span></span><br><span class="line">        System.out.println(doga.getName());<span class="comment">//dogc</span></span><br><span class="line">        System.out.println(doga.getAddress());<span class="comment">//JavaBase.Dog@4554617c，在这里地址就已经发生了改变</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">changeDogName</span><span class="params">(Dog doga)</span> </span>&#123;</span><br><span class="line">        <span class="comment">//在此方法中，修改对象的字段值会修改元对象字段值，因为此时引用的是同一个对象</span></span><br><span class="line">        doga.setName(<span class="string">&quot;dogb&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Dog</span></span>&#123;</span><br><span class="line">    String name;</span><br><span class="line"></span><br><span class="line">    Dog(String name)&#123;</span><br><span class="line">        <span class="keyword">this</span>.name = name;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">getName</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> name;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setName</span><span class="params">(String name)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.name = name;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">getAddress</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">super</span>.toString();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="向下转型（隐式）"><a href="#向下转型（隐式）" class="headerlink" title="向下转型（隐式）"></a>向下转型（隐式）</h3><p>在Java中，是不允许隐式向下转型操作的，这样会使精度降低。</p>
<h4 id="float与double"><a href="#float与double" class="headerlink" title="float与double"></a>float与double</h4><p>float的精度是低于double的，在Java的基础类型中了解到，float是32位，double是64位的，由于存在小于0的情况，所以两个浮点类型都含有一个符号位，1位负数，0位正数，忽略不计。剩余位数中，float有8位指数，23位尾数（小数点之后的位数），double有11位指数，52位尾数。</p>
<p>在挑选使用哪种类型存储时需要从存储与精度中做选择，如果精度重要，则选择double，如果存储更重要，则选择float。</p>
<p><strong>声明</strong></p>
<p>在声明float类型时，需要加上f后缀，来表明这是一个低精度类型，否则会报错（Incompatible types. Found: ‘double’, required: ‘float’）。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">floatAndDouble</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="comment">//直接将1.1赋值给float是隐式向下转型，是不可取的。</span></span><br><span class="line">    <span class="keyword">float</span> f = <span class="number">1.1</span>;<span class="comment">//Incompatible types. Found: &#x27;double&#x27;, required: &#x27;float&#x27;</span></span><br><span class="line">    <span class="keyword">float</span> f = <span class="number">1.1f</span>;</span><br><span class="line">    <span class="keyword">double</span> d = <span class="number">1.1</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="short-与int-int与long"><a href="#short-与int-int与long" class="headerlink" title="short 与int,int与long."></a>short 与int,int与long.</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">shortAndInt</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">int</span> i = <span class="number">1</span>;</span><br><span class="line">    <span class="keyword">short</span> s = i;<span class="comment">//Incompatible types. Found: &#x27;int&#x27;, required: &#x27;short&#x27;,类型不符合/不兼容</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">intAndLong</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">long</span> l = <span class="number">1</span>;</span><br><span class="line">    <span class="keyword">int</span> i = l;<span class="comment">//Incompatible types. Found: &#x27;long&#x27;, required: &#x27;int&#x27;,</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>


<h3 id="逻辑运算符"><a href="#逻辑运算符" class="headerlink" title="逻辑运算符"></a>逻辑运算符</h3><p>||，&amp;&amp;为<strong>逻辑运算符</strong>，</p>
<p>&amp;&amp;（与）：如果两操作数中含有一个假则为假，</p>
<p>||（或）：如果两操作数中含一个真则为真，</p>
<h3 id="运算符"><a href="#运算符" class="headerlink" title="运算符"></a>运算符</h3><p>&amp;、|、^、~、&gt;&gt;、&lt;&lt;、&lt;&lt;&lt;、&gt;&gt;&gt;为<strong>位运算符</strong>，其中三个左大于，右大于是无符号运算。</p>
<p>&amp;：按位与操作，有0则为0，</p>
<table>
<thead>
<tr>
<th align="center">0&amp;0</th>
<th align="center">0</th>
</tr>
</thead>
<tbody><tr>
<td align="center">0&amp;1</td>
<td align="center">0</td>
</tr>
<tr>
<td align="center">1&amp;0</td>
<td align="center">0</td>
</tr>
<tr>
<td align="center">1&amp;1</td>
<td align="center">1</td>
</tr>
</tbody></table>
<p>|：按位或操作，有1则为1</p>
<table>
<thead>
<tr>
<th align="center">0|0</th>
<th align="center">0</th>
</tr>
</thead>
<tbody><tr>
<td align="center">0|1</td>
<td align="center">1</td>
</tr>
<tr>
<td align="center">1|0</td>
<td align="center">1</td>
</tr>
<tr>
<td align="center">1|1</td>
<td align="center">1</td>
</tr>
</tbody></table>
<h3 id="Switch"><a href="#Switch" class="headerlink" title="Switch"></a>Switch</h3><p>从Java7开始，Switch支持在判断语句使用String类型,不支持long,float,double,当然如果条件过于复杂还是弃暗（switch）投明（if）比较好。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">switchAfterJava7</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    String s1 = <span class="string">&quot;1&quot;</span>;</span><br><span class="line">    <span class="keyword">switch</span> (s1)&#123;</span><br><span class="line">        <span class="keyword">case</span> <span class="string">&quot;1&quot;</span>:</span><br><span class="line">            System.out.println(s1);</span><br><span class="line">        <span class="keyword">case</span> <span class="string">&quot;2&quot;</span>:</span><br><span class="line">            System.out.println(s1);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="关键字"><a href="#关键字" class="headerlink" title="关键字"></a>关键字</h2><p>比较重要且常见的关键字有final，static，</p>
<p>Java中所有的关键字：</p>
<p><img src="https://masuo-github-image.oss-cn-beijing.aliyuncs.com/image/20210708235745.png" alt="image-20210708235734472"></p>
<table>
<thead>
<tr>
<th><strong>关键字</strong></th>
<th><strong>含义</strong></th>
</tr>
</thead>
<tbody><tr>
<td>abstract</td>
<td>表明类或者成员方法具有抽象属性</td>
</tr>
<tr>
<td>assert</td>
<td>断言，用来进行程序调试</td>
</tr>
<tr>
<td>boolean</td>
<td>基本数据类型之一，声明布尔类型的关键字</td>
</tr>
<tr>
<td>break</td>
<td>提前跳出一个块</td>
</tr>
<tr>
<td>byte</td>
<td>基本数据类型之一，字节类型</td>
</tr>
<tr>
<td>case</td>
<td>用在switch语句之中，表示其中的一个分支</td>
</tr>
<tr>
<td>catch</td>
<td>用在异常处理中，用来捕捉异常</td>
</tr>
<tr>
<td>char</td>
<td>基本数据类型之一，字符类型</td>
</tr>
<tr>
<td>class</td>
<td>声明一个类</td>
</tr>
<tr>
<td>const</td>
<td>保留关键字，没有具体含义</td>
</tr>
<tr>
<td>continue</td>
<td>回到一个块的开始处</td>
</tr>
<tr>
<td>default</td>
<td>默认，例如，用在switch语句中，表明一个默认的分支。Java8 中也作用于声明接口函数的默认实现</td>
</tr>
<tr>
<td>do</td>
<td>用在do-while循环结构中</td>
</tr>
<tr>
<td>double</td>
<td>基本数据类型之一，双精度浮点数类型</td>
</tr>
<tr>
<td>else</td>
<td>用在条件语句中，表明当条件不成立时的分支</td>
</tr>
<tr>
<td>enum</td>
<td>枚举</td>
</tr>
<tr>
<td>extends</td>
<td>表明一个类型是另一个类型的子类型。对于类，可以是另一个类或者抽象类；对于接口，可以是另一个接口</td>
</tr>
<tr>
<td>final</td>
<td>用来说明最终属性，表明一个类不能派生出子类，或者成员方法不能被覆盖，或者成员域的值不能被改变，用来定义常量</td>
</tr>
<tr>
<td>finally</td>
<td>用于处理异常情况，用来声明一个基本肯定会被执行到的语句块</td>
</tr>
<tr>
<td>float</td>
<td>基本数据类型之一，单精度浮点数类型</td>
</tr>
<tr>
<td>for</td>
<td>一种循环结构的引导词</td>
</tr>
<tr>
<td>goto</td>
<td>保留关键字，没有具体含义</td>
</tr>
<tr>
<td>if</td>
<td>条件语句的引导词</td>
</tr>
<tr>
<td>implements</td>
<td>表明一个类实现了给定的接口</td>
</tr>
<tr>
<td>import</td>
<td>表明要访问指定的类或包</td>
</tr>
<tr>
<td>instance of</td>
<td>用来测试一个对象是否是指定类型的实例对象</td>
</tr>
<tr>
<td>int</td>
<td>基本数据类型之一，整数类型</td>
</tr>
<tr>
<td>interface</td>
<td>接口</td>
</tr>
<tr>
<td>long</td>
<td>基本数据类型之一，长整数类型</td>
</tr>
<tr>
<td>native</td>
<td>用来声明一个方法是由与计算机相关的语言（如C/C++/FORTRAN语言）实现的</td>
</tr>
<tr>
<td>new</td>
<td>用来创建新实例对象</td>
</tr>
<tr>
<td>package</td>
<td>包</td>
</tr>
<tr>
<td>private</td>
<td>一种访问控制方式：私用模式</td>
</tr>
<tr>
<td>protected</td>
<td>一种访问控制方式：保护模式</td>
</tr>
<tr>
<td>public</td>
<td>一种访问控制方式：共用模式</td>
</tr>
<tr>
<td>return</td>
<td>从成员方法中返回数据</td>
</tr>
<tr>
<td>short</td>
<td>基本数据类型之一,短整数类型</td>
</tr>
<tr>
<td>static</td>
<td>表明具有静态属性</td>
</tr>
<tr>
<td>strictfp</td>
<td>用来声明FP_strict（单精度或双精度浮点数）表达式遵循[IEEE 754](<a target="_blank" rel="noopener" href="https://baike.baidu.com/item/IEEE">https://baike.baidu.com/item/IEEE</a> 754)算术规范</td>
</tr>
<tr>
<td>super</td>
<td>表明当前对象的父类型的引用或者父类型的构造方法</td>
</tr>
<tr>
<td>switch</td>
<td>分支语句结构的引导词</td>
</tr>
<tr>
<td>synchronized</td>
<td>表明一段代码需要同步执行</td>
</tr>
<tr>
<td>this</td>
<td>指向当前实例对象的引用</td>
</tr>
<tr>
<td>throw</td>
<td>抛出一个异常</td>
</tr>
<tr>
<td>throws</td>
<td>声明在当前定义的成员方法中所有需要抛出的异常</td>
</tr>
<tr>
<td>transient</td>
<td>声明不用序列化的成员域</td>
</tr>
<tr>
<td>try</td>
<td>尝试一个可能抛出异常的程序块</td>
</tr>
<tr>
<td>void</td>
<td>声明当前成员方法没有返回值</td>
</tr>
<tr>
<td>volatile</td>
<td>表明两个或者多个变量必须同步地发生变化</td>
</tr>
<tr>
<td>while</td>
<td>用在循环结构中</td>
</tr>
</tbody></table>
<p>接下来说一下几个经常用到的，却又是大家（我）不了解的，搞不清楚，稀里糊涂的那些，面试时还经常会问到的。</p>
<h3 id="final"><a href="#final" class="headerlink" title="final"></a>final</h3><p>final我们都知道的这是一个关键字，用来声明那些不会变的常量，其他的迷迷糊糊的就不太清楚了，可能有印象，但是具体到某一个方法，或者类上的时候，就不了解了。这就是我写这篇博客的原因，巩固自己的基础。</p>
<h4 id="①-数据"><a href="#①-数据" class="headerlink" title="①    数据"></a>①    数据</h4><p>声明的数据为常量，可以是编译时常量，也可以是在运行时被初始化后不能被改变的常量。    </p>
<p>​    1）对于基本类型，final使数值不变；</p>
<p>​    2）对于引用类型，final使引用不变，就是引用其他对象，但是被引用的对象本身可以修改。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">finalOnData</span><span class="params">()</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//基本类型</span></span><br><span class="line">    <span class="keyword">final</span> <span class="keyword">int</span> num1 = <span class="number">10</span>;</span><br><span class="line">    <span class="comment">// num1 = 2;//Cannot assign a value to final variable &#x27;num1&#x27;,意思是不能给一个final变量分配值</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">//引用类型</span></span><br><span class="line">    <span class="keyword">final</span> Dog dog = <span class="keyword">new</span> Dog(<span class="string">&quot;doga&quot;</span>);</span><br><span class="line">    System.out.println(dog.getName());<span class="comment">//doga</span></span><br><span class="line">    dog.setName(<span class="string">&quot;dogb&quot;</span>);</span><br><span class="line">    System.out.println(dog.getName());<span class="comment">//dogb</span></span><br><span class="line">    <span class="comment">// dog = new Dog(&quot;dagc&quot;);//Cannot assign a value to final variable &#x27;dog&#x27;</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">//可以看到，对于基本类型，不能改变基本类型变量的值，对于引用类型，不能引用其他对象</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="②-方法"><a href="#②-方法" class="headerlink" title="②    方法"></a>②    方法</h4><p>声明的方法不能被子类重写。private声明的函数被隐式的声明为final类型，因此private类也是不可重写的。当子类中有与父类中的private方法名相同的方法时，这是子类自己的私有方法，与父类私有方法无关，private不像final关键字一样，final声明的方法不可以在子类中存在同名方法，名称相同就不可以，而private运行存在相同的方法名。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Dog</span></span>&#123;</span><br><span class="line">    String name;</span><br><span class="line"></span><br><span class="line">    Dog(String name)&#123;</span><br><span class="line">        <span class="keyword">this</span>.name = name;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">final</span> <span class="keyword">void</span> <span class="title">finalDog</span><span class="params">()</span></span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;这是final方法，不能被重写！&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">DogA</span> <span class="keyword">extends</span> <span class="title">Dog</span></span>&#123;</span><br><span class="line"></span><br><span class="line">    DogA(String name) &#123;</span><br><span class="line">        <span class="keyword">super</span>(name);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">finalDog</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="comment">//&#x27;finalDog()&#x27; cannot override &#x27;finalDog()&#x27; in &#x27;JavaBase.Dog&#x27;; overridden method is final</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="③-类"><a href="#③-类" class="headerlink" title="③    类"></a>③    类</h4><p>最具代表的final类便是基础类型的封装类，如String类，被final声明的类不可以被继承。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">FinalType</span> <span class="keyword">extends</span> <span class="title">String</span></span></span><br><span class="line"><span class="class">//<span class="title">Cannot</span> <span class="title">inherit</span> <span class="title">from</span> <span class="title">final</span> &#x27;<span class="title">java</span>.<span class="title">lang</span>.<span class="title">String</span>&#x27;</span></span><br><span class="line"><span class="class">//不能继承<span class="title">final</span> <span class="title">String</span></span></span><br><span class="line"><span class="class"></span></span><br><span class="line"><span class="class"><span class="title">public</span> <span class="title">final</span> <span class="title">class</span> <span class="title">String</span></span></span><br></pre></td></tr></table></figure>

<h3 id="static"><a href="#static" class="headerlink" title="static"></a>static</h3><h4 id="①-静态变量"><a href="#①-静态变量" class="headerlink" title="①    静态变量"></a>①    静态变量</h4><ul>
<li><p><strong>静态变量</strong>：又称为类变量，也就是说这个变量是属于类的，类的所有实例都共享变量，所以在内存中只存在一份静态变量，可以直接通过类名来访问，也可以通过实例对象来访问（不推荐）。静态变量属于静态存储方式，静态变量不代表值不改变，她的值是可以改变的，但是改了之后就不能回到之前的初始值了。</p>
<p>  JVM只会为静态变量分配一次内存空间，在类加载的时候完成静态变量的内存加载。</p>
<p>  <strong>静态存储</strong>：在程序运行期间分配固定的存储空间。静态存储不一定是静态变量，但是静态变量是静态存储。静态存储需要加上static才能成为静态变量。</p>
</li>
<li><p><strong>实例变量</strong>：每创建一个实例就会产生一个实例变量，他于该实例同生共死。</p>
</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> masuo</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@create</span> 2021/7/10 9:36</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Description</span> static 的使用</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">StaticType</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">int</span> s;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        staticOnData();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * static对数据的使用</span></span><br><span class="line"><span class="comment">     * 1、静态变量</span></span><br><span class="line"><span class="comment">     * 2、实例变量</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">staticOnData</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="comment">//在声明的地方打个断点，在没有执行这一步之前，就已经存在static变量了，</span></span><br><span class="line">        <span class="comment">// 即在调用函数之前static变量就已经存在了，说明静态变量在类加载的时候就存在了，</span></span><br><span class="line">        StaticClassOne sco = <span class="keyword">new</span> StaticClassOne();</span><br><span class="line">      </span><br><span class="line">        <span class="comment">//在执行完声明之后，实例变量x被初始化，</span></span><br><span class="line">        <span class="comment">// 在这里，0是系统默认赋值的，</span></span><br><span class="line">        <span class="keyword">int</span> x = sco.x;<span class="comment">//0</span></span><br><span class="line">        <span class="keyword">int</span> y = StaticClassOne.y;</span><br><span class="line">        System.out.println(<span class="string">&quot;没有改变之前的StaticClassOne.y的值为：&quot;</span>+y);</span><br><span class="line"></span><br><span class="line">        <span class="comment">//改变静态变量</span></span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">10</span>; i++) &#123;</span><br><span class="line">            StaticClassOne.y = StaticClassOne.y+i;</span><br><span class="line">            System.out.println(<span class="string">&quot;改变之后的StaticClassOne.y值为：&quot;</span>+StaticClassOne.y);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">StaticClassOne</span></span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> x; <span class="comment">//实例变量</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">int</span> y = <span class="number">1</span>; <span class="comment">//静态变量</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="②-静态方法"><a href="#②-静态方法" class="headerlink" title="②    静态方法"></a>②    静态方法</h4><p>同静态变量一样，静态方法在类加载的时候就已经存在了，在类加载的时候就存在的都不会依赖实例对象。所以静态方法必须是完整的，不依赖实例对象的存在，要有自己的实现，不能是抽象方法。（抽象与接口的区别在下面会讲到）。</p>
<p>静态方法只能访问该类的静态变量和静态方法。</p>
<p>方法中不能含有this和super等关键字，因为这都是和实体类相关联的。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> masuo</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@create</span> 2021/7/10 16:09</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Description</span> 静态方法测试</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">StaticClassFun</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">get</span><span class="params">()</span></span>;<span class="comment">//Illegal combination of modifiers: &#x27;abstract&#x27; and &#x27;static&#x27;,不合法的修饰符组合</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">void</span> <span class="title">getNO</span><span class="params">()</span></span>;<span class="comment">//正确</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//访问静态变量和访问静态方法</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">get</span><span class="params">()</span></span>&#123;</span><br><span class="line"></span><br><span class="line">    System.out.println(y);<span class="comment">//Non-static field &#x27;y&#x27; cannot be referenced from a static context,非静态变量不可被静态方法引用</span></span><br><span class="line">    System.out.println(x);</span><br><span class="line"></span><br><span class="line">    get();</span><br><span class="line">    getX();</span><br><span class="line">    getAll();<span class="comment">//Non-static method &#x27;getAll()&#x27; cannot be referenced from a static context，非静态方法不可被静态方法引用</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="③-静态语句块"><a href="#③-静态语句块" class="headerlink" title="③    静态语句块"></a>③    静态语句块</h4><p>静态语句块，在类初始化时运行一次，根据Java的类加载机制，类只在需要时被加载，且一次运行只加载一次，在初始化之后，类就存在某个地方（现在还不知道啊，还有好多要学啊，路还很长，只知道她大概是在JVM的内存中，具体是运行时方法区内存区，还是堆【不太可能】或者是别的地方，对于这一块了解的是真的很少。）</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> masuo</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@create</span> 2021/7/10 16:09</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Description</span> 静态方法测试</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">StaticClassFun</span> </span>&#123;</span><br><span class="line">    <span class="keyword">static</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;这是静态语句块，你只会看到我出现一次哦！&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="comment">//在这里我们声明两个StaticClassOne类的实例对象，</span></span><br><span class="line">        StaticClassOne sco1 = <span class="keyword">new</span> StaticClassOne();</span><br><span class="line">        StaticClassOne sco2 = <span class="keyword">new</span> StaticClassOne();</span><br><span class="line">        </span><br><span class="line">        <span class="comment">//至于他只会加载一次的原因，看完以上两个静态变量以及静态方法的描述之后，多少应该会有一点自己的理解吧，在这里类只会加载一次，第二次声明的时候，因为类的pool中已经含有这个类的引用了，所以不会再对这个类进行初始化。</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><img src="https://masuo-github-image.oss-cn-beijing.aliyuncs.com/image/20210710200444.png" alt="image-20210710185119594"></p>
<h4 id="④-静态内部类"><a href="#④-静态内部类" class="headerlink" title="④    静态内部类"></a>④    静态内部类</h4><p>同以上静态变量，静态方法一样，静态内部类是不依赖于外部类的，而非静态内部类是需要依赖于外部类的实例对象的，非静态内部类需要先创建实例对象才能创建非静态内部类。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> masuo</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@create</span> 2021/7/11 12:58</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Description</span> 静态内部类与非静态内部类</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">StaticOuterClass</span> </span>&#123;</span><br><span class="line">    <span class="class"><span class="keyword">class</span> <span class="title">NonStaticInnerClass</span></span>&#123;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">StaticInnerClass</span></span>&#123;</span><br><span class="line">		<span class="comment">//静态内部类不能访问外部类的非静态变量和方法。</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="comment">//非静态内部类不能单独声明</span></span><br><span class="line">        <span class="comment">//NonStaticInnerClass nsic = new NonStaticInnerClass();//&#x27;JavaBase.StaticOuterClass.this&#x27; cannot be referenced from a static context,该类不能从静态上下文引用</span></span><br><span class="line">        </span><br><span class="line">        <span class="comment">//静态内部类可以不依赖实例对象直接声明</span></span><br><span class="line">        StaticInnerClass sic = <span class="keyword">new</span> StaticInnerClass();</span><br><span class="line"></span><br><span class="line">        <span class="comment">//声明外部类的实例对象</span></span><br><span class="line">        StaticOuterClass soc = <span class="keyword">new</span> StaticOuterClass();</span><br><span class="line"></span><br><span class="line">        <span class="comment">//利用外部类的实例对象声明非静态内部类</span></span><br><span class="line">        NonStaticInnerClass nsic = soc.<span class="function">new <span class="title">NonStaticInnerClass</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h4 id="⑤-静态导包"><a href="#⑤-静态导包" class="headerlink" title="⑤    静态导包"></a>⑤    静态导包</h4><p>静态导包的作用是简化代码，具体参考：<a target="_blank" rel="noopener" href="https://blog.csdn.net/u012338954/article/details/51010337">https://blog.csdn.net/u012338954/article/details/51010337</a></p>
<h4 id="⑥-初始化顺序"><a href="#⑥-初始化顺序" class="headerlink" title="⑥    初始化顺序"></a>⑥    初始化顺序</h4><p>到了最重要的地方，这里一定要认真仔细的看，去理解，上面已经讲得说的很细了（在我看来）。</p>
<p>首先，静态变量具有很高的优先级，静态变量与静态语句块取决于他们在代码中的顺序。</p>
<p>在这里需要提一下一个经典的问题，<strong>Java中类加载的问题</strong>！！！</p>
<p>例：引用于：<a target="_blank" rel="noopener" href="https://blog.csdn.net/zfx2013/article/details/89453482">https://blog.csdn.net/zfx2013/article/details/89453482</a></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> masuo</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@create</span> 2021/7/11 22:34</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Description</span> java类的初始化循序</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">JavaClassInitSequence</span> </span>&#123;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/** 输出顺序为</span></span><br><span class="line"><span class="comment">     *  1.父类静态（变量或者代码块）显式赋值，</span></span><br><span class="line"><span class="comment">     *  2.子类静态（变量或者代码块）显式赋值，</span></span><br><span class="line"><span class="comment">     *  3.父类非静态显式赋值（变量或代码块）</span></span><br><span class="line"><span class="comment">     *  4.父类构造函数</span></span><br><span class="line"><span class="comment">     *  5.子类非静态显式赋值（变量或代码块）</span></span><br><span class="line"><span class="comment">     *  6.子类构造函数</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     *  ***注意这里是显式赋值，首先必须是赋值语句，如果没有赋值语句，只是单纯的声明变量/或初始化变量，则不会输出，看注释1</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        Cat d = <span class="keyword">new</span> Cat();</span><br><span class="line">        <span class="comment">//①父类静态fm,fa.②子类静态ss,sm.③父类非静态ft,fn,a.④子类非静态sa,st,sd</span></span><br><span class="line">        System.out.println(<span class="string">&quot;000&quot;</span>);</span><br><span class="line">        Cat o = <span class="keyword">new</span> Cat();</span><br><span class="line">        <span class="comment">//</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Animal</span></span>&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">int</span> i = test();</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">int</span> j = method();</span><br><span class="line">    <span class="comment">//注释1：下面两行代码不会输出，因为他们不是显式赋值语句,隐式赋值即implicit(x)</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">int</span> x;</span><br><span class="line">    </span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;fa&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    Animal()&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;a&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;fn&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">int</span> <span class="title">test</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;ft&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">int</span> <span class="title">method</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;fm&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">int</span> <span class="title">implicit</span><span class="params">(<span class="keyword">int</span> i)</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;ft&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> i;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Cat</span> <span class="keyword">extends</span> <span class="title">Animal</span></span>&#123;</span><br><span class="line">    &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;sa&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">int</span> i = test();</span><br><span class="line">    <span class="keyword">static</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;ss&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">int</span> j = method();</span><br><span class="line"></span><br><span class="line">    Cat()&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;sd&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">test</span><span class="params">()</span></span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;st&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">int</span> <span class="title">method</span><span class="params">()</span></span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;sm&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>输出顺序为<br>      1.父类静态（变量或者代码块）<strong>显式赋值</strong>，<br>      2.子类静态（变量或者代码块）<strong>显式赋值</strong>，<br>      3.父类非静态显式赋值（变量或代码块）<br>      4.父类构造函数<br>      5.子类非静态显式赋值（变量或代码块）<br>      6.子类构造函数</p>
<h3 id="instanceof"><a href="#instanceof" class="headerlink" title="instanceof"></a>instanceof</h3><p>参考：<a target="_blank" rel="noopener" href="https://www.cnblogs.com/ysocean/p/8486500.html">https://www.cnblogs.com/ysocean/p/8486500.html</a></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">boolean</span> result = obj <span class="keyword">instanceof</span> Class</span><br></pre></td></tr></table></figure>

<p><strong>概述</strong>：根据定义来看，可以说instanceof是一个Java的双目运算符，双目运算符就是需要两个变量才能运算的运算符，可以想象为==，用来测试<strong>左侧对象</strong>是否是<strong>右侧类</strong>的实例。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">List&lt;String&gt; ls = <span class="keyword">new</span> ArrayList&lt;&gt;();</span><br><span class="line">System.out.println(ls.getClass());<span class="comment">//class java.util.ArrayList</span></span><br><span class="line">System.out.println(ls <span class="keyword">instanceof</span> Collection);<span class="comment">//true</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//在这里，ls是ArrayList类，ArrayList是List的接口实现类，List是Collection的子类，</span></span><br></pre></td></tr></table></figure>

<p>但是使用instanceof有以下几点需要注意：</p>
<ul>
<li>obj必须为引用类型，不能是基础类型</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//基础类型</span></span><br><span class="line"><span class="keyword">char</span> c = <span class="string">&#x27;1&#x27;</span>;</span><br><span class="line">System.out.println(c <span class="keyword">instanceof</span> String);</span><br><span class="line"><span class="comment">//Inconvertible types; cannot cast &#x27;char&#x27; to &#x27;java.lang.String&#x27;</span></span><br></pre></td></tr></table></figure>



<ul>
<li>NULL</li>
</ul>
<p>NULL是一个特殊的类型，可以是任意引用类型的特殊符号，可能是因为所有类都有空值，所以所有类型都有null。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//null</span></span><br><span class="line">System.out.println(<span class="keyword">null</span> <span class="keyword">instanceof</span> Object);<span class="comment">//false</span></span><br></pre></td></tr></table></figure>



<ul>
<li>obj为class类的实例对象</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//class类的实例对象</span></span><br><span class="line">String s = <span class="string">&quot;123&quot;</span>;</span><br><span class="line">System.out.println(s <span class="keyword">instanceof</span> String);<span class="comment">//true</span></span><br></pre></td></tr></table></figure>



<ul>
<li>obj为class接口的实现类</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//接口实现类，如ArrayList是AbstractList的子类，是List等的接口实现类</span></span><br><span class="line">List&lt;String&gt; ls2 = <span class="keyword">new</span> ArrayList&lt;&gt;();</span><br><span class="line">System.out.println(ls2 <span class="keyword">instanceof</span> List);<span class="comment">//true</span></span><br></pre></td></tr></table></figure>



<ul>
<li>obj为class的直接或间接子类</li>
</ul>
<p>看过第一个实例的话，我觉得你应该有自己的答案了。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//直接或间接子类</span></span><br><span class="line">List&lt;String&gt; ls3 = <span class="keyword">new</span> ArrayList&lt;&gt;();</span><br><span class="line">System.out.println(ls3 <span class="keyword">instanceof</span> AbstractCollection);<span class="comment">//true</span></span><br><span class="line"><span class="comment">//在这里ls3是ArrayList类，ArrayList类是AbstractList类的子类，AbstractList类是AbstractCollection类的子类。</span></span><br></pre></td></tr></table></figure>



<h3 id="native"><a href="#native" class="headerlink" title="native"></a>native</h3><p>首先，native多用在方法上。</p>
<p>native方法就是Java调用非Java代码的接口，所以你见到的Java中含native关键字的方法大多都没有方法体，因为他们都是通过外接代码实现的。而使用native的主要原因是因为Java无法对操作系统底层进行操作，但是可以同过JNI（Java native interface）调用其他语言来实现底层访问。</p>
<h3 id="构造方法"><a href="#构造方法" class="headerlink" title="构造方法"></a>构造方法</h3><p>构造方法名与类名必须保持完全一致，包括类型及变量。</p>
<p>构造方法不含类型</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Test</span>(<span class="title">int</span> <span class="title">i</span>)</span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">Test</span><span class="params">(<span class="keyword">int</span> i)</span></span>&#123;</span><br><span class="line">        <span class="comment">//构造方法在new一个新的对象时会自动被调用</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h2 id="Object"><a href="#Object" class="headerlink" title="Object"></a>Object</h2><p>作为用的最少（本人之前是不怎么使用Object类的）却又儿孙满堂的Object类，可以说是既遥远却又近在眼前的了，说他遥远是因为目前我们很少会用到他，说他近是因为我们无时不刻在使用他的子类。</p>
<p>他作为最大的父类一共提供了十一个方法。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">native</span> Class&lt;?&gt; getClass();</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">native</span> <span class="keyword">int</span> <span class="title">hashCode</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">equals</span><span class="params">(Object obj)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> (<span class="keyword">this</span> == obj);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">native</span> Object <span class="title">clone</span><span class="params">()</span> <span class="keyword">throws</span> CloneNotSupportedException</span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> String <span class="title">toString</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> getClass().getName() + <span class="string">&quot;@&quot;</span> + Integer.toHexString(hashCode());</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">native</span> <span class="keyword">void</span> <span class="title">notify</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">native</span> <span class="keyword">void</span> <span class="title">notifyAll</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">native</span> <span class="keyword">void</span> <span class="title">wait</span><span class="params">(<span class="keyword">long</span> timeout)</span> <span class="keyword">throws</span> InterruptedException</span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">void</span> <span class="title">wait</span><span class="params">(<span class="keyword">long</span> timeout, <span class="keyword">int</span> nanos)</span> <span class="keyword">throws</span> InterruptedException </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (timeout &lt; <span class="number">0</span>) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException(<span class="string">&quot;timeout value is negative&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (nanos &lt; <span class="number">0</span> || nanos &gt; <span class="number">999999</span>) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException(</span><br><span class="line">            <span class="string">&quot;nanosecond timeout value out of range&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (nanos &gt; <span class="number">0</span>) &#123;</span><br><span class="line">        timeout++;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    wait(timeout);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">void</span> <span class="title">wait</span><span class="params">()</span> <span class="keyword">throws</span> InterruptedException </span>&#123;</span><br><span class="line">    wait(<span class="number">0</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">finalize</span><span class="params">()</span> <span class="keyword">throws</span> Throwable </span>&#123; &#125;</span><br></pre></td></tr></table></figure>



<h3 id="equals"><a href="#equals" class="headerlink" title="equals"></a>equals</h3><ul>
<li><p>基础类型：只能用==来判断相等，判断的是值相等</p>
</li>
<li><p>引用类型：使用equals判断他们是否等价，使用==判断的是他们两个是否引用同一个对象。</p>
<h6 id="实现："><a href="#实现：" class="headerlink" title="实现："></a>实现：</h6><ul>
<li>首先判断是否引用同一个对象</li>
<li>其次判断是否同一个类型</li>
</ul>
</li>
</ul>
<p>Object的equals()实现</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">equals</span><span class="params">(Object obj)</span> </span>&#123;</span><br><span class="line">    <span class="comment">//==：双等号在Java中判断的是两个值是否引用同一个对象</span></span><br><span class="line">    <span class="comment">//判断两个对象是否引用同一个对象</span></span><br><span class="line">    <span class="keyword">return</span> (<span class="keyword">this</span> == obj);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>String的equals()实现</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">equals</span><span class="params">(Object anObject)</span> </span>&#123;</span><br><span class="line">    <span class="comment">//与Object相同</span></span><br><span class="line">    <span class="keyword">if</span> (<span class="keyword">this</span> == anObject) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//不同的话，判断该对象是否是String类型，在这里有关instanceof的知识可以往上面找</span></span><br><span class="line">    <span class="keyword">if</span> (anObject <span class="keyword">instanceof</span> String) &#123;</span><br><span class="line">        <span class="comment">//在这里对对象进行强转，</span></span><br><span class="line">        String anotherString = (String)anObject;</span><br><span class="line">        <span class="comment">//获取自身的长度，这个value是String中早就声明好的final对象，</span></span><br><span class="line">        <span class="comment">//private final char value[];，注意Java8中String还在使用char数组存储字符串，之后则使用byte数组</span></span><br><span class="line">        <span class="keyword">int</span> n = value.length;</span><br><span class="line">        <span class="comment">//获取传进来的object对象的长度，并比较他们是否长度相等</span></span><br><span class="line">        <span class="keyword">if</span> (n == anotherString.value.length) &#123;</span><br><span class="line">            <span class="comment">//将自己的数组赋值给v1</span></span><br><span class="line">            <span class="keyword">char</span> v1[] = value;</span><br><span class="line">            <span class="comment">//获取传进来的object对象的数组，这里上面再进行强转的时候object对象已经有了数组</span></span><br><span class="line">            <span class="keyword">char</span> v2[] = anotherString.value;</span><br><span class="line">            <span class="keyword">int</span> i = <span class="number">0</span>;</span><br><span class="line">            <span class="comment">//长度不为0的时候，持续循环</span></span><br><span class="line">            <span class="keyword">while</span> (n-- != <span class="number">0</span>) &#123;</span><br><span class="line">                <span class="comment">//值不相等，则返回false，相等则i++，循环</span></span><br><span class="line">                <span class="keyword">if</span> (v1[i] != v2[i])</span><br><span class="line">                    <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">                i++;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="hashcode"><a href="#hashcode" class="headerlink" title="hashcode"></a>hashcode</h3><p>这个大家一定都很熟了吧，hashcode，哈希值，又称散列值，所以object的hashcode（）方法就是返回对象的哈希值，相等的两个对象哈希值一定相等，但是不相等的两个值散列值，不一定不相等。因为散列值具有随机性，两个值不相等的对象可能算出相同的hash值。</p>
<p>在equals方法覆盖到的地方，同时可以覆盖hashcode方法，保证<strong>等价</strong>的两个对象具有相同的hash值。</p>
<p>HashSet()方法和HashMap()方法使用了hashcode方法计算对象的存储位置。因此添加到其中的类都实现了hashcode()方法。如果自定义类没有实现hashcode方法，那么他们看起来一样但是不能保证散列值相同，也不能确定他们是相等的。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">hashcodeTest</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="comment">//等价性</span></span><br><span class="line">    System.out.println(<span class="string">&quot;hashcode&quot;</span>);</span><br><span class="line">    String s1 = <span class="string">&quot;12333999&quot;</span>;</span><br><span class="line">    String s2 = <span class="string">&quot;123&quot;</span>;</span><br><span class="line">    System.out.println(s1.equals(s2));<span class="comment">//true</span></span><br><span class="line">    System.out.println(s1.hashCode());<span class="comment">//48690</span></span><br><span class="line">    System.out.println(s2.hashCode());<span class="comment">//48690</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="keyword">char</span> []val = &#123;<span class="string">&#x27;1&#x27;</span>,<span class="string">&#x27;2&#x27;</span>,<span class="string">&#x27;3&#x27;</span>,<span class="string">&#x27;4&#x27;</span>,<span class="string">&#x27;5&#x27;</span>,<span class="string">&#x27;6&#x27;</span>,<span class="string">&#x27;7&#x27;</span>,<span class="string">&#x27;9&#x27;</span>,<span class="string">&#x27;9&#x27;</span>,<span class="string">&#x27;9&#x27;</span>,<span class="string">&#x27;9&#x27;</span>&#125;;</span><br><span class="line">    <span class="keyword">int</span> h = <span class="number">0</span>;</span><br><span class="line">    <span class="comment">//int最大值是2的31次方-1，这里int类型是32位，一位符号位标识正负，初始化为0，表示正数，</span></span><br><span class="line">    <span class="comment">// 当数值大于2的31次方-1时会产生进位操作，导致数值变负数，</span></span><br><span class="line">    <span class="comment">// 2的31次方-1 = 2147483647</span></span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; val.length; i++) &#123;</span><br><span class="line">        System.out.println(Integer.valueOf(val[i]));</span><br><span class="line">        h = <span class="number">31</span> * h + val[i];</span><br><span class="line">        System.out.println(h);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>在上面我对hashcode的源码产生了一个疑惑，现在来对hashcode的源码进行解析一下。</p>
<p>源码：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">hashCode</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">int</span> h = hash;<span class="comment">//0</span></span><br><span class="line">    <span class="comment">//private int hash; 官方的解释： Default to 0，默认值为0</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">//h为0保证了只会进入一次，也就是说，hashcode获取一次后就不再改变了</span></span><br><span class="line">    <span class="keyword">if</span> (h == <span class="number">0</span> &amp;&amp; value.length &gt; <span class="number">0</span>) &#123;</span><br><span class="line">        <span class="comment">//将value数组clone给val</span></span><br><span class="line">        <span class="keyword">char</span> val[] = value;</span><br><span class="line">		<span class="comment">//当i小于数组长度时，持续循环</span></span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; value.length; i++) &#123;</span><br><span class="line">            <span class="comment">//计算h得值</span></span><br><span class="line">            h = <span class="number">31</span> * h + val[i];</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//赋值给hash，以后直接通过hash获取</span></span><br><span class="line">        hash = h;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//返回hash值</span></span><br><span class="line">    <span class="keyword">return</span> h;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>源码很简单，但是其中存在一个坑，也是我的疑惑，那就是当我的数组足够长时，h的值很快就会超过int类型的上限值（2147483647），此时循环仍在继续，int就会突破上限，临时提升为long类型，之后再取范围内的int值并返回，之间的具体过程可以参考：<a target="_blank" rel="noopener" href="https://blog.csdn.net/u011123972/article/details/90265415">https://blog.csdn.net/u011123972/article/details/90265415</a> 。非常感谢这位大佬的解疑。</p>
<p>==在这里R取31是有原因的，31是一个奇素数，奇数能保证信息不会丢失，如果是偶数的话，信息就会丢失。因为与2相乘相当于向左位移一位，最左边的位丢失。==</p>
<h3 id="toString-NaN"><a href="#toString-NaN" class="headerlink" title="toString"></a>toString</h3><p>在一些自定义的类中，在那些toString还没被重写的类中，会输出包名+类名+@+十六进制字符串的形式</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">toStringTest</span><span class="params">()</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    ToString ts = <span class="keyword">new</span> ToString();</span><br><span class="line">    System.out.println(ts.toString());<span class="comment">//JavaBase.ToString@1b6d3586</span></span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>String类的toString方法</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">String s = <span class="string">&quot;123&quot;</span>;</span><br><span class="line">s.toString();</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">toString</span><span class="params">()</span> </span>&#123;</span><br><span class="line">     <span class="keyword">return</span> <span class="keyword">this</span>;</span><br><span class="line"> &#125;</span><br></pre></td></tr></table></figure>

<p>Integer类的toString方法</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">Integer i = <span class="number">1</span>;</span><br><span class="line">i.toString();</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> String <span class="title">toString</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> toString(value);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="clone"><a href="#clone" class="headerlink" title="clone"></a>clone</h3><h4 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h4><p>clone()是Object的protected方法，不是public，一个类不显式地去写clone方法，其他类就不能直接去调用该类的clone方法。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">cloneTest</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="class"><span class="keyword">class</span> <span class="title">CloneTest1</span></span>&#123;</span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">protected</span> Object <span class="title">clone</span><span class="params">()</span> <span class="keyword">throws</span> CloneNotSupportedException </span>&#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">super</span>.clone();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="class"><span class="keyword">class</span> <span class="title">CloneTest2</span></span>&#123;</span><br><span class="line">        <span class="comment">//无clone方法</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    CloneTest1 ct1 = <span class="keyword">new</span> CloneTest1();</span><br><span class="line">    CloneTest2 ct2 = <span class="keyword">new</span> CloneTest2();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        ct1.clone();<span class="comment">//java.lang.CloneNotSupportedException: JavaBase.SeeObject$1CloneTest1</span></span><br><span class="line">        <span class="comment">//在这里看似CloneTest1类可以调用clone方法，但是实际上还是会抛出不支持克隆的异常</span></span><br><span class="line">    &#125; <span class="keyword">catch</span> (CloneNotSupportedException e) &#123;</span><br><span class="line">        e.printStackTrace();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//ct2.clone();//&#x27;clone()&#x27; has protected access in &#x27;java.lang.Object&#x27;</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>我们看一下Object的clone方法源码</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">native</span> Object <span class="title">clone</span><span class="params">()</span> <span class="keyword">throws</span> CloneNotSupportedException</span>;</span><br></pre></td></tr></table></figure>

<p>可以看到，因为native的原因这里并没有代码体，因为这不是Java的原生代码，而是外接代码实现，但是可以抛出异常，当我们实现cloneable的接口后，就不会报错了。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">CloneTest1</span> <span class="keyword">implements</span> <span class="title">Cloneable</span></span>&#123;<span class="comment">//实现接口</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">protected</span> Object <span class="title">clone</span><span class="params">()</span> <span class="keyword">throws</span> CloneNotSupportedException </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> (CloneTest1)<span class="keyword">super</span>.clone();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="浅拷贝"><a href="#浅拷贝" class="headerlink" title="浅拷贝"></a>浅拷贝</h4><p>拷贝对象和原始对象的引用类型引用同一个对象。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">skinCloneTest</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    System.out.println(<span class="string">&quot;浅拷贝&quot;</span>);</span><br><span class="line">    <span class="class"><span class="keyword">class</span> <span class="title">SkinClone</span> <span class="keyword">implements</span> <span class="title">Cloneable</span></span>&#123;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">int</span> i ;<span class="comment">//default 0</span></span><br><span class="line">        <span class="comment">//首先，声明clone方法</span></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">protected</span> SkinClone <span class="title">clone</span><span class="params">()</span> <span class="keyword">throws</span> CloneNotSupportedException </span>&#123;</span><br><span class="line">            <span class="keyword">return</span> (SkinClone)<span class="keyword">super</span>.clone();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">//构造方法</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="title">SkinClone</span><span class="params">()</span></span>&#123;</span><br><span class="line">            i = <span class="number">10</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">getI</span><span class="params">()</span> </span>&#123;</span><br><span class="line">            <span class="keyword">return</span> i;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setI</span><span class="params">(<span class="keyword">int</span> i)</span> </span>&#123;</span><br><span class="line">            <span class="keyword">this</span>.i = i;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    SkinClone sct1 = <span class="keyword">new</span> SkinClone();</span><br><span class="line">    sct1.setI(<span class="number">50</span>);</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        SkinClone sct2 = sct1.clone();</span><br><span class="line">        <span class="comment">// j</span></span><br><span class="line">        System.out.println(sct2.getI() == sct1.getI());</span><br><span class="line">        <span class="comment">// 输出true，说明是同一个对象，浅拷贝</span></span><br><span class="line">    &#125; <span class="keyword">catch</span> (CloneNotSupportedException e) &#123;</span><br><span class="line">        e.printStackTrace();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="深拷贝"><a href="#深拷贝" class="headerlink" title="深拷贝"></a>深拷贝</h4><p>拷贝对象和原始对象的引用类型引用不同对象。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">BoneCloneTest</span><span class="params">()</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    System.out.println(<span class="string">&quot;深拷贝&quot;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="class"><span class="keyword">class</span> <span class="title">BoneClone</span> <span class="keyword">implements</span> <span class="title">Cloneable</span></span>&#123;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">private</span> String s ;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">protected</span> BoneClone <span class="title">clone</span><span class="params">()</span> <span class="keyword">throws</span> CloneNotSupportedException </span>&#123;</span><br><span class="line">            <span class="comment">//深拷贝需要new操作，来新建对象</span></span><br><span class="line">            BoneClone clone = (BoneClone) <span class="keyword">super</span>.clone();</span><br><span class="line">            <span class="comment">//新建一个对象表示引用不同的对象</span></span><br><span class="line">            clone.s = <span class="keyword">new</span> String(s);</span><br><span class="line">            <span class="keyword">return</span> clone;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">//构造类</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="title">BoneClone</span><span class="params">()</span></span>&#123;</span><br><span class="line">            s = <span class="string">&quot;s&quot;</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> String <span class="title">getS</span><span class="params">()</span> </span>&#123;</span><br><span class="line">            <span class="keyword">return</span> s;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setS</span><span class="params">(String s)</span> </span>&#123;</span><br><span class="line">            <span class="keyword">this</span>.s = s;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    BoneClone bc1 = <span class="keyword">new</span> BoneClone();</span><br><span class="line">    bc1.setS(<span class="string">&quot;555&quot;</span>);</span><br><span class="line">    BoneClone bc2 = <span class="keyword">null</span>;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        bc2 = bc1.clone();</span><br><span class="line">    &#125; <span class="keyword">catch</span> (CloneNotSupportedException e) &#123;</span><br><span class="line">        e.printStackTrace();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">assert</span> bc2 != <span class="keyword">null</span>;</span><br><span class="line">    <span class="comment">// 假设黑盒测试</span></span><br><span class="line">    System.out.println(bc2.getS() == bc1.getS());<span class="comment">//555</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="关于clone的建议"><a href="#关于clone的建议" class="headerlink" title="关于clone的建议"></a>关于clone的建议</h4><p>经过上面的简单实验，可以发现其实Object自带的clone还算顺手，但是当我们我遇到比较复杂的类的时候，就会显得比较不顺手了，而且对于新手搞不懂异常的时候，就会经常抛出异常，而且需要类型转换，很不是友好。</p>
<p>Effective Java 书上讲到，最好不要去使⽤ clone()，可以使⽤拷⻉构造函数或者拷⻉⼯⼚来拷⻉⼀个对象。</p>
<p>这里可以研究一下Array List的iterator方法。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">CloneConstructorTest</span><span class="params">()</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="class"><span class="keyword">class</span> <span class="title">CloneConstructor</span></span>&#123;</span><br><span class="line">        <span class="keyword">private</span> String s;</span><br><span class="line"></span><br><span class="line">        <span class="comment">//构造函数</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="title">CloneConstructor</span><span class="params">()</span></span>&#123;</span><br><span class="line">            s = <span class="string">&quot;&quot;</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> String <span class="title">getS</span><span class="params">()</span> </span>&#123;</span><br><span class="line">            <span class="keyword">return</span> s;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setS</span><span class="params">(String s)</span> </span>&#123;</span><br><span class="line">            <span class="keyword">this</span>.s = s;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * 克隆构造方法，原理与构造方法类似，不同点在于需要获取原始对象数据，并将拷贝对象的数据赋值给拷贝对象</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="title">CloneConstructor</span><span class="params">(CloneConstructor original)</span></span>&#123;</span><br><span class="line">            <span class="comment">//代替clone方法，</span></span><br><span class="line">            <span class="keyword">this</span>.s = original.s;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>更详细的可参考：<a target="_blank" rel="noopener" href="https://blog.csdn.net/j2ee_infinite/article/details/9473395">https://blog.csdn.net/j2ee_infinite/article/details/9473395</a></p>
<p>其余方法与线程或JVM的GC相关，之后再提。</p>
<h2 id="继承"><a href="#继承" class="headerlink" title="继承"></a>继承</h2><h3 id="访问权限"><a href="#访问权限" class="headerlink" title="访问权限"></a>访问权限</h3><p>Java中有三个访问权限修饰符：private，protected，public，如果不加访问修饰符，则默认包级可见default。</p>
<table>
<thead>
<tr>
<th>访问权限修饰符</th>
<th>同一个类</th>
<th>同一个包</th>
<th>不同包的子类</th>
<th>不同包的非子类</th>
</tr>
</thead>
<tbody><tr>
<td>private</td>
<td>√</td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>default</td>
<td>√</td>
<td>√</td>
<td></td>
<td></td>
</tr>
<tr>
<td>protected</td>
<td>√</td>
<td>√</td>
<td>√</td>
<td></td>
</tr>
<tr>
<td>public</td>
<td>√</td>
<td>√</td>
<td>√</td>
<td>√</td>
</tr>
</tbody></table>
<ul>
<li>类可见表示其他类可以用这个类创建对象</li>
<li>成员可见表示其他类可用这个类的实例对象访问到该成员或方法</li>
</ul>
<h3 id="抽象类与接口"><a href="#抽象类与接口" class="headerlink" title="抽象类与接口"></a>抽象类与接口</h3><p>老生常谈的话题了，由于抽象类只能被继承所以他的大部分字段及方法为public。</p>
<table>
<thead>
<tr>
<th>异同</th>
<th>抽象类</th>
<th>接口</th>
</tr>
</thead>
<tbody><tr>
<td>关键字</td>
<td>abstract</td>
<td>interface</td>
</tr>
<tr>
<td>方法体</td>
<td>抽象方法无方法体，非抽象方法可以存在方法体</td>
<td>可以有方法体，default声明的方法必须有方法体</td>
</tr>
<tr>
<td>实例化</td>
<td>不能被实例化</td>
<td>可以被实例化</td>
</tr>
<tr>
<td>继承/实现</td>
<td>√</td>
<td>√</td>
</tr>
<tr>
<td>字段默认</td>
<td>无</td>
<td>默认为public，static，final，不允许定义为private或protected，在java9之后可以定义为private，</td>
</tr>
<tr>
<td>方法默认</td>
<td>无</td>
<td>默认为public</td>
</tr>
</tbody></table>
<h4 id="抽象类"><a href="#抽象类" class="headerlink" title="抽象类"></a>抽象类</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">AbstractTest</span></span>&#123;</span><br><span class="line">    <span class="comment">//类声明时带有abstrac则表明这是一个抽象类</span></span><br><span class="line">    </span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">int</span> i;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">//抽象方法不可以存在方法体，同时在方法声明时使用abstract则必须将整个类声明为abstract</span></span><br><span class="line">    <span class="function"><span class="keyword">abstract</span> <span class="keyword">void</span> <span class="title">fun1</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">fun2</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="comment">//非抽象方法必须存在方法体</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h6 id="继承-1"><a href="#继承-1" class="headerlink" title="继承"></a>继承</h6><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">AbstractTest1</span> <span class="keyword">extends</span> <span class="title">AbstractTest</span></span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">fun1</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="comment">//必须继承abstract方法</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="接口类"><a href="#接口类" class="headerlink" title="接口类"></a>接口类</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">InterfaceTest</span></span>&#123;</span><br><span class="line">    <span class="comment">//接口中的字段和方法默认都是public的，无需添加</span></span><br><span class="line">    <span class="comment">//接口声明常量时必须初始化，且都是static和final的</span></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">int</span> i = <span class="number">0</span>;<span class="comment">//Modifier &#x27;static&#x27; is redundant for interface fields</span></span><br><span class="line">    <span class="keyword">final</span> <span class="keyword">int</span> j = <span class="number">0</span>;<span class="comment">//Modifier &#x27;final&#x27; is redundant for interface fields</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> y = <span class="number">0</span>;<span class="comment">//Modifier &#x27;public&#x27; is redundant for interface fields</span></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">fun1</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">default</span> <span class="keyword">void</span> <span class="title">fun2</span><span class="params">()</span></span>&#123;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">default</span> <span class="keyword">void</span> <span class="title">fun3</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="comment">//Modifier &#x27;public&#x27; is redundant for interface methods</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h6 id="实例化"><a href="#实例化" class="headerlink" title="实例化"></a>实例化</h6><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">InterfaceTest interfaceTest = <span class="keyword">new</span> InterfaceTest() &#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">fun1</span><span class="params">()</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<h4 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h4><p>（参考自：<a target="_blank" rel="noopener" href="https://zhuanlan.zhihu.com/p/84593550%EF%BC%89">https://zhuanlan.zhihu.com/p/84593550）</a></p>
<p>语法层面的区别：</p>
<ol>
<li>接口可以提供具体的实现方法，而抽象类只能提供方法名</li>
<li>接口中的变量类型是单一的（只能是public static final），而抽象类中的变量类型是多种多样的</li>
<li>接口中不能含有静态代码块和静态方法，但是抽象类中可以</li>
<li>一个类只能继承一个抽象类，但是可以实现多个接口类。</li>
</ol>
<p>设计层面的区别：</p>
<ol>
<li>抽象类是对实物的抽象，是“是不是”的思想，是IS-A的思想；接口是“有没有”的思想，是HAS-A的思想，比如抽象类：人，如何判断是不是“人”，则是抽象类需要做的事情，而决定你是‘1’还是‘0’则是接口的需要做的事情。</li>
<li>设计层面不同，对于抽象类，是模板式设计；对于接口类，是辐射式设计。修改抽象类可以选择使用带方法体的非抽象方法，而不影响子类；修改接口类则子类也会跟着修改。</li>
</ol>
<p>==tips：接口优于抽象类使用，因为不是所有的东西都可以抽象出公共特点，且接口可以多个继承==</p>
<h3 id="super"><a href="#super" class="headerlink" title="super"></a>super</h3><ul>
<li>访问父类的构造函数：可以使用super来访问父类的构造函数，委托父类完成初始化。再调用子类时，一定会调用父类的构造函数，但是一般会调用父类的默认的构造函数，可以使用super调用其他构造函数。</li>
<li>访问父类的成员：如果子类中重写了父类的方法，此时还想调用此方法的话可以通过super方法调用。</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> masuo</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@create</span> 2021/7/14 11:01</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Description</span> super</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SuperExample</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        SuperExample se = <span class="keyword">new</span> SuperExample();</span><br><span class="line">        se.superTest();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">superTest</span><span class="params">()</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">        Son son = <span class="keyword">new</span> Son(<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>);</span><br><span class="line">        son.fun();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="class"><span class="keyword">class</span> <span class="title">Father</span></span>&#123;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">int</span> i;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">int</span> j;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="title">Father</span><span class="params">()</span></span>&#123;</span><br><span class="line">            <span class="comment">//默认构造函数</span></span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="title">Father</span><span class="params">(<span class="keyword">int</span> i,<span class="keyword">int</span> j)</span></span>&#123;</span><br><span class="line">            <span class="comment">//带参数非默认构造函数</span></span><br><span class="line">            <span class="keyword">this</span>.i = i;</span><br><span class="line">            <span class="keyword">this</span>.j = j;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">void</span> <span class="title">fun</span><span class="params">()</span></span>&#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;father fun&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="class"><span class="keyword">class</span> <span class="title">Son</span> <span class="keyword">extends</span> <span class="title">Father</span></span>&#123;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">int</span> i;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">int</span> j;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">int</span> x;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="title">Son</span><span class="params">()</span></span>&#123;</span><br><span class="line">            <span class="comment">//默认构造函数</span></span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="title">Son</span><span class="params">(<span class="keyword">int</span> i,<span class="keyword">int</span> j, <span class="keyword">int</span> x)</span></span>&#123;</span><br><span class="line">            <span class="keyword">super</span>(i, j);</span><br><span class="line">            <span class="keyword">this</span>.x = x;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@Override</span></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">fun</span><span class="params">()</span> </span>&#123;</span><br><span class="line">            <span class="keyword">super</span>.fun();</span><br><span class="line">            System.out.println(<span class="string">&quot;son fun&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="重写与重载"><a href="#重写与重载" class="headerlink" title="重写与重载"></a>重写与重载</h3><h4 id="区别"><a href="#区别" class="headerlink" title="区别"></a>区别</h4><table>
<thead>
<tr>
<th>名称</th>
<th>重写（over write）</th>
<th>重载（over load）</th>
</tr>
</thead>
<tbody><tr>
<td>存在于</td>
<td>继承关系中</td>
<td>同一个类中</td>
</tr>
<tr>
<td>实现</td>
<td>重写父类方法体</td>
<td>改变参数个数或类型</td>
</tr>
<tr>
<td></td>
<td>@Override</td>
<td></td>
</tr>
</tbody></table>
<h4 id="重写"><a href="#重写" class="headerlink" title="重写"></a>重写</h4><p>重写存在于继承关系中，指子类实现了一个与父类在方法声明上完全相同的一个方法。</p>
<p>重写需满足里氏替换原则：</p>
<ul>
<li>子类方法的访问权限必须大于等于父类</li>
<li>子类的返回类型必须是父类返回类型或子类型</li>
<li>子类抛出的异常必须是父类异常的类型或子类型</li>
</ul>
<p>可以使用@Override来检验自己的方法是不是满足里氏替换原则</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">overWrite</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="comment">//发生在父类与子类之间</span></span><br><span class="line">    <span class="class"><span class="keyword">class</span> <span class="title">Father</span> <span class="keyword">extends</span> <span class="title">Object</span></span>&#123;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">int</span> i;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">funAccessControl</span><span class="params">()</span></span>&#123;</span><br><span class="line">            <span class="comment">//默认包级可见</span></span><br><span class="line">            System.out.println(<span class="string">&quot;父类访问控制权限为protected。&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">protected</span> Father <span class="title">funReturnType</span><span class="params">()</span></span>&#123;</span><br><span class="line">            <span class="comment">//默认包级可见</span></span><br><span class="line">            System.out.println(<span class="string">&quot;父类返回类型为Father&quot;</span>);</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">new</span> Father();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">funException</span><span class="params">()</span><span class="keyword">throws</span> Throwable</span>&#123;</span><br><span class="line">            <span class="comment">//默认包级可见</span></span><br><span class="line">            System.out.println(<span class="string">&quot;fun&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="class"><span class="keyword">class</span> <span class="title">Son</span> <span class="keyword">extends</span> <span class="title">Father</span></span>&#123;</span><br><span class="line">        <span class="comment">/** 满足里氏替换原则</span></span><br><span class="line"><span class="comment">             * 1.访问控制权限大于等于父类</span></span><br><span class="line"><span class="comment">             * 2.返回类型是父类返回类型或其子类</span></span><br><span class="line"><span class="comment">             * 3.抛出异常为父类异常或其子类</span></span><br><span class="line"><span class="comment">             */</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">//            private void funAccessControl()&#123;</span></span><br><span class="line">        <span class="comment">//                //&#x27;funAccessControl()&#x27; in &#x27;Son&#x27; clashes with &#x27;funAccessControl()&#x27; in &#x27;Father&#x27;; attempting to assign weaker access privileges (&#x27;private&#x27;); was &#x27;protected&#x27;</span></span><br><span class="line">        <span class="comment">//                //本人翻译水平有限，有道翻译为：&#x27;Son&#x27;中的&#x27;funAccessControl()&#x27;与&#x27;Father&#x27;中的&#x27;funAccessControl()&#x27;冲突;试图分配较弱的访问权限(&#x27;private&#x27;);“保护”</span></span><br><span class="line">        <span class="comment">//                System.out.println(&quot;子类访问控制权限为private。未通过。&quot;);</span></span><br><span class="line">        <span class="comment">//            &#125;</span></span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">funAccessControl</span><span class="params">()</span></span>&#123;</span><br><span class="line">            <span class="comment">//</span></span><br><span class="line">            System.out.println(<span class="string">&quot;子类访问控制权限为public。通过。&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">//            public Father funReturnType()&#123;</span></span><br><span class="line">        <span class="comment">//                //Incompatible types. Found: &#x27;java.lang.Object&#x27;, required: &#x27;Father&#x27;</span></span><br><span class="line">        <span class="comment">//                //不兼容的类型，</span></span><br><span class="line">        <span class="comment">//                return new Object();</span></span><br><span class="line">        <span class="comment">//            &#125;</span></span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> Father <span class="title">funReturnType</span><span class="params">()</span></span>&#123;</span><br><span class="line">            <span class="comment">//</span></span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">new</span> Son();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">funException</span><span class="params">()</span> <span class="keyword">throws</span> Exception</span>&#123;</span><br><span class="line">            <span class="comment">//</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    Father son = <span class="keyword">new</span> Son();</span><br><span class="line">    son.fun();</span><br><span class="line">    son.funAccessControl();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        son.funException();</span><br><span class="line">    &#125; <span class="keyword">catch</span> (Throwable throwable) &#123;</span><br><span class="line">        throwable.printStackTrace();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    son.funReturnType();</span><br><span class="line">    System.out.println(son.toString());</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>输出结果：</p>
<figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">这是子类没有的父类方法。</span><br><span class="line">子类访问控制权限为public。通过。</span><br><span class="line">子类 funReturnType的返回类型是Son，Father的子类。</span><br><span class="line">JavaBase.OverWriteOROverLoad$1Son@1b6d3586</span><br></pre></td></tr></table></figure>

<p>所以输出顺序为：</p>
<p>本身的方法优先，如果在自身方法中没有找到该方法，则去父类寻找。</p>
<p>在父类中找不到则在往上一级父类中寻找直到首次找到该方法。</p>
<p>总结就是</p>
<ul>
<li>this.fun(this) </li>
<li>super.fun(this)</li>
<li>this.fun(super)</li>
<li>super.fun(super)</li>
</ul>
<h4 id="重载"><a href="#重载" class="headerlink" title="重载"></a>重载</h4><p>存在于同一个类中，指一个方法与此类中已经存在的方法同名，但是参数类型或参数个数或参数顺序中有一个不相同。</p>
<p>返回值不同，但是方法名一样，不算重载。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> masuo</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@create</span> 2021/7/15 22:37</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Description</span> 重载</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">OverLoad</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">fun</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="comment">//无参数</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">fun</span><span class="params">(<span class="keyword">int</span> i)</span></span>&#123;</span><br><span class="line">        <span class="comment">//有一个参数</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">fun</span><span class="params">(<span class="keyword">int</span> i,<span class="keyword">int</span> j)</span></span>&#123;</span><br><span class="line">        <span class="comment">//有两个参数</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">fun</span><span class="params">(String s)</span></span>&#123;</span><br><span class="line">        <span class="comment">//有一个参数，类型不同</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function">String <span class="title">fun</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="comment">//返回值不同，但是方法名一样，不算重载，不可行</span></span><br><span class="line">        <span class="comment">//&#x27;fun()&#x27; is already defined in &#x27;JavaBase.OverLoad&#x27;</span></span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;00&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h2 id="容器"><a href="#容器" class="headerlink" title="容器"></a>容器</h2><p>概述：首先来说一下，在Java中什么是容器？</p>
<p>在Java中，如果有一个类专门用来存放其他类的对象，这个类就叫容器，或者集合。</p>
<p>容器主要包括Collection和Map两种，Collection是对象的集合，Map键值对的映射。来看一下这两个的结构。</p>
<p><img src="https://masuo-github-image.oss-cn-beijing.aliyuncs.com/image/20210717224314.jpg" alt="preview"></p>
<p>（虚线的方框代表这个类是接口类，实体方框嗲表他是一个可实现类。）</p>
<p>先总结一下自己整理完集合以及自己已掌握的知识做的一张表</p>
<table>
<thead>
<tr>
<th align="center">类</th>
<th align="center">存储</th>
</tr>
</thead>
<tbody><tr>
<td align="center">Collection</td>
<td align="center">数据集合</td>
</tr>
<tr>
<td align="center">Map</td>
<td align="center">Key-value</td>
</tr>
</tbody></table>
<table>
<thead>
<tr>
<th align="center">类</th>
<th align="center">底层实现</th>
<th align="center">性能</th>
<th align="center">重复性</th>
<th>排序</th>
<th>安全性</th>
</tr>
</thead>
<tbody><tr>
<td align="center">ArrayList</td>
<td align="center">数组</td>
<td align="center">查询快，增删慢</td>
<td align="center">可重复</td>
<td>不排序</td>
<td>线程不安全</td>
</tr>
<tr>
<td align="center">LinkedList</td>
<td align="center">双向链表</td>
<td align="center">增删快，查询慢</td>
<td align="center"></td>
<td></td>
<td>线程不安全</td>
</tr>
<tr>
<td align="center">HashMap</td>
<td align="center">K-V数组</td>
<td align="center">查询快，增删较慢</td>
<td align="center">key可null，不可重复</td>
<td>无序</td>
<td>线程不安全</td>
</tr>
<tr>
<td align="center">LinkedHashMap</td>
<td align="center">HashMap+双向链表</td>
<td align="center">同HashMap</td>
<td align="center"></td>
<td>插入顺序和访问顺序根据AccessOrder参数设置</td>
<td>线程不安全</td>
</tr>
<tr>
<td align="center">TreeMap</td>
<td align="center">红黑树</td>
<td align="center">增删慢，</td>
<td align="center"></td>
<td>有序，红黑树</td>
<td>线程不安全</td>
</tr>
<tr>
<td align="center">ConcurrentHashMap</td>
<td align="center">HashMap+锁</td>
<td align="center">同HashMap</td>
<td align="center">同HashMap</td>
<td>同HashMap</td>
<td>线程安全</td>
</tr>
<tr>
<td align="center">HashSet</td>
<td align="center">HashMap</td>
<td align="center"></td>
<td align="center">无重复</td>
<td></td>
<td></td>
</tr>
<tr>
<td align="center">TreeSet</td>
<td align="center">TreeMap</td>
<td align="center"></td>
<td align="center"></td>
<td>插入顺序</td>
<td></td>
</tr>
</tbody></table>
<h3 id="Collection"><a href="#Collection" class="headerlink" title="Collection"></a>Collection</h3><p>主要是单个元素的集合，包括List，set，queue三个<strong>接口</strong>，三种不同的实现方式。</p>
<h5 id="Collections"><a href="#Collections" class="headerlink" title="Collections"></a>Collections</h5><p>在这里需要注意一个Collections类，这个类是一个公共私有类，为什么说他是一个公共私有类，都公共了还怎么私有呢？这里就是关键字private的作用了。我们来看一下Collections的构造函数。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Suppresses default constructor, ensuring non-instantiability.</span></span><br><span class="line"><span class="function"><span class="keyword">private</span> <span class="title">Collections</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="comment">//正是这个private让他变成一个私有类，不可以被实例化，</span></span><br><span class="line">    <span class="comment">//学到了，如果建立一个公共类但是不想被实例化的话，可以使用私有化构造函数解决</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h5 id="Collection和Collections有什么不同？"><a href="#Collection和Collections有什么不同？" class="headerlink" title="Collection和Collections有什么不同？"></a>Collection和Collections有什么不同？</h5><ul>
<li>collection是一个接口，提供了提供了集合对象的基础通用接口</li>
<li>collections是一个公共私有类，不能被实例化，但是包含很多静态类。想要使用她的方法，我们可以使用类名+方法名（参数）的方法去调用。</li>
</ul>
<h4 id="List"><a href="#List" class="headerlink" title="List"></a>List</h4><p>List的特点在于元素<strong>可重复</strong>，主要分为ArrayList和LinkedList，还有一个vector类。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">    List&lt;String&gt; lv = <span class="keyword">new</span> Vector&lt;&gt;();</span><br><span class="line"></span><br><span class="line">    List&lt;String&gt; la = <span class="keyword">new</span> ArrayList&lt;&gt;();</span><br><span class="line"></span><br><span class="line">    List&lt;String&gt; ll = <span class="keyword">new</span> LinkedList&lt;&gt;();</span><br><span class="line">    </span><br><span class="line">    List&lt;String&gt; ls = <span class="keyword">new</span> Stack&lt;&gt;();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h5 id="Array-List"><a href="#Array-List" class="headerlink" title="Array List"></a>Array List</h5><p>Array List底层由数组完成，且他是一个动态增长的数组，初始长度为10.</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> DEFAULT_CAPACITY = <span class="number">10</span>;<span class="comment">//ArrayList数组的默认长度为10</span></span><br></pre></td></tr></table></figure>

<p>在Java中声明一个数组是需要长度的，所以Java中数组的长度是固定的，但是Array List的长度是不固定的。来看一下它是如何实现动态增长的吧。</p>
<p>首先他有两个构造函数来应对有参构造以及无参构造，当然他不止这两个构造函数，还有上面提到的clone构造函数。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Constructs an empty list with the specified initial capacity.</span></span><br><span class="line"><span class="comment"> * 有参构造，使用特殊的初始化容量构造一个空的list，在这里特殊的初始化容量就是传进来的参数</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span>  initialCapacity  the initial capacity of the list</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@throws</span> IllegalArgumentException if the specified initial capacity</span></span><br><span class="line"><span class="comment"> *         is negative</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">//这个方法在我们这个样声明时调用：List&lt;String&gt; al1 = new ArrayList&lt;&gt;(10);</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">ArrayList</span><span class="params">(<span class="keyword">int</span> initialCapacity)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (initialCapacity &gt; <span class="number">0</span>) &#123;</span><br><span class="line">        <span class="keyword">this</span>.elementData = <span class="keyword">new</span> Object[initialCapacity];</span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (initialCapacity == <span class="number">0</span>) &#123;</span><br><span class="line">        <span class="keyword">this</span>.elementData = EMPTY_ELEMENTDATA;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException(<span class="string">&quot;Illegal Capacity: &quot;</span>+</span><br><span class="line">                                           initialCapacity);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Constructs an empty list with an initial capacity of ten.</span></span><br><span class="line"><span class="comment"> * 使用默认初始化容量10构造一个空的list</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="comment">//这个方法在我们这个样声明时调用：List&lt;String&gt; al2 = new ArrayList&lt;&gt;();</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">ArrayList</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">this</span>.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>可以看到，这两个构造函数还是蛮简单的，很容易懂.</p>
<p>接下来看看当我们往数组中添加数据时会发生什么。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">ArrayListTest</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    List&lt;String&gt; al1 = <span class="keyword">new</span> ArrayList&lt;&gt;(<span class="number">2</span>);</span><br><span class="line">    List&lt;String&gt; al2 = <span class="keyword">new</span> ArrayList&lt;&gt;();<span class="comment">//第一步，初始化进入无参构造方法</span></span><br><span class="line">    al2.add(<span class="string">&quot;1&quot;</span>);<span class="comment">//第二步，</span></span><br><span class="line">    al2.add(<span class="string">&quot;2&quot;</span>);</span><br><span class="line">    al2.add(<span class="string">&quot;3&quot;</span>);</span><br><span class="line">    al2.add(<span class="string">&quot;4&quot;</span>);</span><br><span class="line">    al2.add(<span class="string">&quot;5&quot;</span>);</span><br><span class="line">    al2.add(<span class="string">&quot;6&quot;</span>);</span><br><span class="line">    al2.add(<span class="string">&quot;7&quot;</span>);</span><br><span class="line">    al2.add(<span class="string">&quot;8&quot;</span>);</span><br><span class="line">    al2.add(<span class="string">&quot;9&quot;</span>);</span><br><span class="line">    al2.add(<span class="string">&quot;10&quot;</span>);<span class="comment">//</span></span><br><span class="line">    al2.add(<span class="string">&quot;11&quot;</span>);</span><br><span class="line">    al2.add(<span class="string">&quot;12&quot;</span>);</span><br><span class="line">    al2.add(<span class="string">&quot;13&quot;</span>);</span><br><span class="line">    al2.add(<span class="string">&quot;14&quot;</span>);</span><br><span class="line">    al2.add(<span class="string">&quot;15&quot;</span>);</span><br><span class="line">    al2.add(<span class="string">&quot;16&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>第一步</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//初始化时会先进入这个构造方法，elementData时用来存放数据的，非常重要，要时刻关注她的变化。</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">ArrayList</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">this</span>.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;</span><br><span class="line">    <span class="comment">//这个时候elementdata的长度是0，与此同时modCount被赋值为0</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//DEFAULTCAPACITY_EMPTY_ELEMENTDATA：默认初始化为一个空数组</span></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = &#123;&#125;;</span><br></pre></td></tr></table></figure>

<p>第二步</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//调用add函数，在add函数中，</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">add</span><span class="params">(E e)</span> </span>&#123;</span><br><span class="line">    <span class="comment">//执行ensureCapacityInternal:确保内部容量，因为本次需要add一个数据，在刚进入add的时候，此时数据还没被加到数组中，需要判断数组容量是否足够，所以需要将size+1在进行判断，判断过程在第三步</span></span><br><span class="line">    <span class="comment">//足够则执行下一步：elementData[size++] = e;，</span></span><br><span class="line">    <span class="comment">//不足够的话，会调用grow，下面会提到</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">//第三步</span></span><br><span class="line">    ensureCapacityInternal(size + <span class="number">1</span>);  <span class="comment">// Increments modCount!!</span></span><br><span class="line">    elementData[size++] = e;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>第三步</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//ensureCapacityInternal：确保内部容量足够，之后进入 calculateCapacity 方法</span></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">ensureCapacityInternal</span><span class="params">(<span class="keyword">int</span> minCapacity)</span> </span>&#123;</span><br><span class="line">     <span class="comment">//这里的两个参数分别代表存储数据的数组elementData，存储数据最低需要的容量minCapacity</span></span><br><span class="line">     </span><br><span class="line">     <span class="comment">//进入第四步</span></span><br><span class="line">     ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));</span><br><span class="line"> &#125;</span><br></pre></td></tr></table></figure>

<p>第四步</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//calculateCapacity：计算容量，在这一步会算出最低所需容量并返回，之后会返回  ensureCapacityInternal 方法，并进入 ensureExplicitCapacity 这个方法</span></span><br><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">int</span> <span class="title">calculateCapacity</span><span class="params">(Object[] elementData, <span class="keyword">int</span> minCapacity)</span> </span>&#123;</span><br><span class="line">    <span class="comment">//首先判断是不是第一次添加数据，如果是第一次则从默认数组长度与初始化时设置的数组长度中返回较大的数据作为elementdata的长度</span></span><br><span class="line">    <span class="keyword">if</span> (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) &#123;</span><br><span class="line">        <span class="keyword">return</span> Math.max(DEFAULT_CAPACITY, minCapacity);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> minCapacity;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">//之后进入第五步</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>第五步</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//ensureExplicitCapacity：确保显式容量，在这一步中,会确认elementdata的长度</span></span><br><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">ensureExplicitCapacity</span><span class="params">(<span class="keyword">int</span> minCapacity)</span> </span>&#123;</span><br><span class="line">    <span class="comment">//这个参数是指当前列表被修改的次数</span></span><br><span class="line">    modCount++;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// overflow-conscious code</span></span><br><span class="line">    <span class="comment">//注意：这里的minCapacity是指数组中数组的个数，即size，而elementData.length是数组的长度，数组的长度声明之后是不能变的，这两个是不相等的，在这里相比较的就是这两个数值，当然这个size是+1之后的size</span></span><br><span class="line">    <span class="comment">//当size的大小大于length的时候，说明数组长度已经不够了，需要扩容</span></span><br><span class="line">    <span class="keyword">if</span> (minCapacity - elementData.length &gt; <span class="number">0</span>)</span><br><span class="line">        <span class="comment">//第六步</span></span><br><span class="line">        grow(minCapacity);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>第六步</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//grow:扩容机制是如何运行的呢？下面我们来一起看看吧。</span></span><br><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">grow</span><span class="params">(<span class="keyword">int</span> minCapacity)</span> </span>&#123;</span><br><span class="line">    <span class="comment">// overflow-conscious code</span></span><br><span class="line">    <span class="keyword">int</span> oldCapacity = elementData.length;<span class="comment">//旧的容量等于还没扩容的elementdata的数组长度</span></span><br><span class="line">    <span class="keyword">int</span> newCapacity = oldCapacity + (oldCapacity &gt;&gt; <span class="number">1</span>);<span class="comment">//新的容量等于旧容量的1.5倍，至于为什么是1.5倍，需要去了解一下位运算的&#x27;&gt;&gt;&#x27;运算，</span></span><br><span class="line">    <span class="keyword">if</span> (newCapacity - minCapacity &lt; <span class="number">0</span>)</span><br><span class="line">        <span class="comment">//如果新容量小于新容量，至于这个你可能会产生一个疑问，怎么可能，都1.5倍了，但是别忘了，还有容量为0的时候呢，0的1.5倍还是0哦。</span></span><br><span class="line">        newCapacity = minCapacity;</span><br><span class="line">    	<span class="comment">//将minCapacity赋值给newCapacity，这里minCapacity最小都会是10，不会再小了</span></span><br><span class="line">    </span><br><span class="line">    </span><br><span class="line">    <span class="keyword">if</span> (newCapacity - MAX_ARRAY_SIZE &gt; <span class="number">0</span>)</span><br><span class="line">        <span class="comment">//这一步是保证数组长度不会超过int的承受范围，如果你的数组有需求，可以更长，这在现在就不细讲了，总之你要知道，他最长的长度是整数的最大值，但是为了避免出现错误才减8，如OutOfMenmory，</span></span><br><span class="line">        newCapacity = hugeCapacity(minCapacity);</span><br><span class="line">    <span class="comment">// minCapacity is usually close to size, so this is a win:</span></span><br><span class="line">    </span><br><span class="line">    </span><br><span class="line">    <span class="comment">//将数组中的数据复制给扩容后的数组。数组长度变大</span></span><br><span class="line">    elementData = Arrays.copyOf(elementData, newCapacity);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> MAX_ARRAY_SIZE = Integer.MAX_VALUE - <span class="number">8</span>;</span><br></pre></td></tr></table></figure>

<p>以上就是ArrayList的初始化以及扩容机制。希望你能看懂。</p>
<h6 id="优缺点"><a href="#优缺点" class="headerlink" title="优缺点"></a>优缺点</h6><p>使用数组作为底层的优点就是访问速度够快，但是增删慢。因为数组是有序的放在内存上的，只需按照下标去找就可以直接找到。</p>
<h6 id="与vector的区别"><a href="#与vector的区别" class="headerlink" title="与vector的区别"></a>与vector的区别</h6><p>vector了解即可，都说这是一个已经过时的知识点。（但是还有很多参考价值）</p>
<ul>
<li>线程安全：vector是线程安全的，ArrayList是非线程安全的</li>
<li>性能：Array List性能优于vector，因为他在操作数据时会上锁，所以很费时间</li>
<li>扩容机制：vector每次扩容都会增加一倍，而ArrayList每次只会扩大1.5倍。</li>
</ul>
<h5 id="Linked-List"><a href="#Linked-List" class="headerlink" title="Linked List"></a>Linked List</h5><p>LinkedList底层是由双向链表实现的，没有初始容量，链表嘛，想要扩容往下寻址链接即可。</p>
<p>先来简单看下源码吧，到了这一步，看源码是了解他最快的方式。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//size代表数据量，同ArrayList的size</span></span><br><span class="line"><span class="keyword">transient</span> <span class="keyword">int</span> size = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/** 指向第一个数据</span></span><br><span class="line"><span class="comment"> * Pointer to first node.</span></span><br><span class="line"><span class="comment"> * Invariant: (first == null &amp;&amp; last == null) ||</span></span><br><span class="line"><span class="comment"> *            (first.prev == null &amp;&amp; first.item != null)</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">transient</span> Node&lt;E&gt; first;</span><br><span class="line"></span><br><span class="line"><span class="comment">/** 指向最后一个数据</span></span><br><span class="line"><span class="comment"> * Pointer to last node.</span></span><br><span class="line"><span class="comment"> * Invariant: (first == null &amp;&amp; last == null) ||</span></span><br><span class="line"><span class="comment"> *            (last.next == null &amp;&amp; last.item != null)</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">transient</span> Node&lt;E&gt; last;</span><br><span class="line"></span><br><span class="line"><span class="comment">/** 无参构造函数</span></span><br><span class="line"><span class="comment"> * Constructs an empty list.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">LinkedList</span><span class="params">()</span> </span>&#123;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/** 有参构造函数</span></span><br><span class="line"><span class="comment"> * Constructs a list containing the elements of the specified</span></span><br><span class="line"><span class="comment"> * collection, in the order they are returned by the collection&#x27;s</span></span><br><span class="line"><span class="comment"> * iterator.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span>  c the collection whose elements are to be placed into this list</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@throws</span> NullPointerException if the specified collection is null</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">LinkedList</span><span class="params">(Collection&lt;? extends E&gt; c)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">this</span>();</span><br><span class="line">    addAll(c);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>这里面出现最多的就是这个Node了，那么这个Node又是什么呢？</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//这个Node是LinkedList的内部私有类，含有三个变量以及一个构造函数，</span></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Node</span>&lt;<span class="title">E</span>&gt; </span>&#123;</span><br><span class="line">    E item;</span><br><span class="line">    Node&lt;E&gt; next;</span><br><span class="line">    Node&lt;E&gt; prev;</span><br><span class="line"></span><br><span class="line">    Node(Node&lt;E&gt; prev, E element, Node&lt;E&gt; next) &#123;</span><br><span class="line">        <span class="keyword">this</span>.item = element;<span class="comment">//自己</span></span><br><span class="line">        <span class="keyword">this</span>.next = next;<span class="comment">//指向下一个</span></span><br><span class="line">        <span class="keyword">this</span>.prev = prev;<span class="comment">//指向前一个</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>嗯，就是这样的，前后一个节点，中间是自己。</p>
<p>来个例子看看吧。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">LinkedListTest</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    System.out.println(<span class="string">&quot;linked list test&quot;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">//第一步，声明一下，看看如何初始化的</span></span><br><span class="line">    List&lt;String&gt; ls = <span class="keyword">new</span> LinkedList&lt;&gt;();</span><br><span class="line"></span><br><span class="line">    <span class="comment">//加数据，因为有前后中，所以数据大于等于3就行，</span></span><br><span class="line">    <span class="comment">//第二步</span></span><br><span class="line">    ls.add(<span class="string">&quot;1&quot;</span>);</span><br><span class="line">    ls.add(<span class="string">&quot;2&quot;</span>);</span><br><span class="line">    ls.add(<span class="string">&quot;3&quot;</span>);</span><br><span class="line">    ls.add(<span class="string">&quot;4&quot;</span>);</span><br><span class="line">    ls.add(<span class="string">&quot;5&quot;</span>);</span><br><span class="line"></span><br><span class="line">    System.out.println(ls);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<p>第一步</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/** 进入一个无参构造函数</span></span><br><span class="line"><span class="comment"> * Constructs an empty list.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">LinkedList</span><span class="params">()</span> </span>&#123;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//到声明结束与ArrayList大致一致</span></span><br></pre></td></tr></table></figure>

<p>第二步</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/** 往数组尾部加数据</span></span><br><span class="line"><span class="comment"> * Appends the specified element to the end of this list.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * &lt;p&gt;This method is equivalent to &#123;<span class="doctag">@link</span> #addLast&#125;.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> e element to be appended to this list</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> &#123;<span class="doctag">@code</span> true&#125; (as specified by &#123;<span class="doctag">@link</span> Collection#add&#125;)</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">add</span><span class="params">(E e)</span> </span>&#123;</span><br><span class="line">    <span class="comment">//第三步</span></span><br><span class="line">    linkLast(e);</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>第三步</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/** 将e链接为最后一个元素</span></span><br><span class="line"><span class="comment"> * Links e as last element.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">linkLast</span><span class="params">(E e)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">final</span> Node&lt;E&gt; l = last;<span class="comment">//null</span></span><br><span class="line">    <span class="keyword">final</span> Node&lt;E&gt; newNode = <span class="keyword">new</span> Node&lt;&gt;(l, e, <span class="keyword">null</span>);<span class="comment">//这一步就是将自己放入里面</span></span><br><span class="line">    last = newNode;<span class="comment">//之后将自己变成上一个节点，毕竟自己已经被放进来了，就老了</span></span><br><span class="line">    <span class="comment">//到这里，前后基本都赋值完成了</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">//之后，这里是判断是不是第一次执行，第一次执行需要给first赋值，将第一个插入的同时也将他变成第一个节点，如果不是第一次，将新节点链接到上一个节点</span></span><br><span class="line">    <span class="keyword">if</span> (l == <span class="keyword">null</span>)</span><br><span class="line">        first = newNode;</span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">        l.next = newNode;</span><br><span class="line">    <span class="comment">//容量以及操作数+1</span></span><br><span class="line">    size++;</span><br><span class="line">    modCount++;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>后面的就是重复第三步了。</p>
<p>具体可参考：<a target="_blank" rel="noopener" href="https://zhuanlan.zhihu.com/p/28101975">https://zhuanlan.zhihu.com/p/28101975</a></p>
<h6 id="优缺点-1"><a href="#优缺点-1" class="headerlink" title="优缺点"></a>优缺点</h6><p>由于底层是用双向链表实现的，可以看到增删改都比较简单（只需将删除节点的前后指向修改一下即可，并将本节点使得前后指向为null），但是查看的时候需要遍历数组，如果你要找的节点在最后一个，那好吧你需要全部循环一遍，但是使用数组为底层的时候只需找到相应下标即可。</p>
<p>还可以用作栈，队列和双向队列。</p>
<h4 id="Set"><a href="#Set" class="headerlink" title="Set"></a>Set</h4><p>同样，Set有两个子类HashSet和TreeSet，HashSet又包括LinkedHashSet，在此之前需要我们先掌握Map相关的知识，所以尽量先看看Map吧。</p>
<p>先来看一下结构图。</p>
<p><img src="https://masuo-github-image.oss-cn-beijing.aliyuncs.com/image/20210726144113.png" alt="image-20210726144110781"></p>
<h6 id="HashSet"><a href="#HashSet" class="headerlink" title="HashSet"></a>HashSet</h6><p>来看一下源码吧，如你不想通过源码来了解一个类，你还可以通过他顶部的注释来了解她的特性以及用法，我们来看一下</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * A collection that contains no duplicate elements.（无重复对象的集合）  </span></span><br><span class="line"><span class="comment"> * More formally, sets</span></span><br><span class="line"><span class="comment"> * contain no pair of elements &lt;code&gt;e1&lt;/code&gt; and &lt;code&gt;e2&lt;/code&gt; such that</span></span><br><span class="line"><span class="comment"> * &lt;code&gt;e1.equals(e2)&lt;/code&gt;, and at most one null element（最多有一个null对象）. </span></span><br><span class="line"><span class="comment"> * As implied by</span></span><br><span class="line"><span class="comment"> * its name, this interface models the mathematical &lt;i&gt;set&lt;/i&gt; abstraction.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * &lt;p&gt;The &lt;tt&gt;Set&lt;/tt&gt; interface places additional stipulations, beyond those</span></span><br><span class="line"><span class="comment"> * inherited from the &lt;tt&gt;Collection&lt;/tt&gt; interface, on the contracts of all</span></span><br><span class="line"><span class="comment"> * constructors and on the contracts of the &lt;tt&gt;add&lt;/tt&gt;, &lt;tt&gt;equals&lt;/tt&gt; and</span></span><br><span class="line"><span class="comment"> * &lt;tt&gt;hashCode&lt;/tt&gt; methods.  Declarations for other inherited methods are</span></span><br><span class="line"><span class="comment"> * also included here for convenience.  (The specifications accompanying these</span></span><br><span class="line"><span class="comment"> * declarations have been tailored to the &lt;tt&gt;Set&lt;/tt&gt; interface, but they do</span></span><br><span class="line"><span class="comment"> * not contain any additional stipulations.)</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * Note that this implementation is not synchronized.不同步的</span></span><br><span class="line"><span class="comment"> */</span></span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">long</span> serialVersionUID = -<span class="number">5024744406713321676L</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">transient</span> HashMap&lt;E,Object&gt; map;</span><br><span class="line"></span><br><span class="line"><span class="comment">// Dummy value to associate with an Object in the backing Map</span></span><br><span class="line"><span class="comment">// 与后台映射中的对象关联的虚拟值，即所有的value都是（Present）object，毕竟Hash Set是以Hash Map为底层实现的</span></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> Object PRESENT = <span class="keyword">new</span> Object();</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">HashSet</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    map = <span class="keyword">new</span> HashMap&lt;&gt;();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">HashSet</span><span class="params">(Collection&lt;? extends E&gt; c)</span> </span>&#123;</span><br><span class="line">    map = <span class="keyword">new</span> HashMap&lt;&gt;(Math.max((<span class="keyword">int</span>) (c.size()/<span class="number">.75f</span>) + <span class="number">1</span>, <span class="number">16</span>));</span><br><span class="line">    addAll(c);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">HashSet</span><span class="params">(<span class="keyword">int</span> initialCapacity, <span class="keyword">float</span> loadFactor)</span> </span>&#123;</span><br><span class="line">    map = <span class="keyword">new</span> HashMap&lt;&gt;(initialCapacity, loadFactor);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">HashSet</span><span class="params">(<span class="keyword">int</span> initialCapacity)</span> </span>&#123;</span><br><span class="line">    map = <span class="keyword">new</span> HashMap&lt;&gt;(initialCapacity);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">HashSet(<span class="keyword">int</span> initialCapacity, <span class="keyword">float</span> loadFactor, <span class="keyword">boolean</span> dummy) &#123;</span><br><span class="line">    map = <span class="keyword">new</span> LinkedHashMap&lt;&gt;(initialCapacity, loadFactor);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>可以看到，到处都是HashMap的知识，所以先了解HashMap是没错的。</p>
<p><strong>特性</strong>：</p>
<ul>
<li>只允许一个null（跟HashMap中key只允许有一个null相同）</li>
<li>没有重复对象（值相等）</li>
<li>不保证迭代顺序（同HashMap）</li>
<li>不同步（线程不安全）</li>
</ul>
<h6 id="TreeSet"><a href="#TreeSet" class="headerlink" title="TreeSet"></a>TreeSet</h6><p>TreeSet与HashSet的不同就在于TreeSet是有序的，而且她的底层是Tree Map</p>
<h4 id="Queue"><a href="#Queue" class="headerlink" title="Queue"></a>Queue</h4><h3 id="Map"><a href="#Map" class="headerlink" title="Map"></a>Map</h3><p>我们都知道Map是以键值对&lt;Key,Value&gt;的形式保存数据的，</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">Map</span>&lt;<span class="title">K</span>,<span class="title">V</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>在Map中最重要的便是如下三个集合，在这里面你可能会产生的一个疑问就是K，V分别是什么？</p>
<p>这么说，这是Java5就已经存在的一个特性了-泛型，具体可参考：<a target="_blank" rel="noopener" href="https://www.jianshu.com/p/41a7a975502d">https://www.jianshu.com/p/41a7a975502d</a> 。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Views</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//key，键</span></span><br><span class="line"><span class="function">Set&lt;K&gt; <span class="title">keySet</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">//value，值</span></span><br><span class="line"><span class="function">Collection&lt;V&gt; <span class="title">values</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">//entry，键值对</span></span><br><span class="line">Set&lt;Map.Entry&lt;K, V&gt;&gt; entrySet();</span><br><span class="line"></span><br><span class="line"><span class="comment">//这里这个Entry是Map的一个内部接口类</span></span><br><span class="line"><span class="class"><span class="keyword">interface</span> <span class="title">Entry</span>&lt;<span class="title">K</span>,<span class="title">V</span>&gt; </span>&#123;</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Returns the key corresponding to this entry.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function">K <span class="title">getKey</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Returns the value corresponding to this entry.  </span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function">V <span class="title">getValue</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Replaces the value corresponding to this entry with the specified</span></span><br><span class="line"><span class="comment">     * value (optional operation).  </span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function">V <span class="title">setValue</span><span class="params">(V value)</span></span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Compares the specified object with this entry for equality.</span></span><br><span class="line"><span class="comment">         </span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">boolean</span> <span class="title">equals</span><span class="params">(Object o)</span></span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Returns the hash code value for this map entry.  </span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">int</span> <span class="title">hashCode</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Returns a comparator that compares &#123;<span class="doctag">@link</span> Map.Entry&#125; in natural order on key.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> &lt;K extends Comparable&lt;? <span class="keyword">super</span> K&gt;, V&gt; Comparator&lt;Map.Entry&lt;K,V&gt;&gt; comparingByKey() &#123;</span><br><span class="line">        <span class="keyword">return</span> (Comparator&lt;Map.Entry&lt;K, V&gt;&gt; &amp; Serializable)</span><br><span class="line">            (c1, c2) -&gt; c1.getKey().compareTo(c2.getKey());</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Returns a comparator that compares &#123;<span class="doctag">@link</span> Map.Entry&#125; in natural order on value.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> &lt;K, V extends Comparable&lt;? <span class="keyword">super</span> V&gt;&gt; Comparator&lt;Map.Entry&lt;K,V&gt;&gt; comparingByValue() &#123;</span><br><span class="line">        <span class="keyword">return</span> (Comparator&lt;Map.Entry&lt;K, V&gt;&gt; &amp; Serializable)</span><br><span class="line">            (c1, c2) -&gt; c1.getValue().compareTo(c2.getValue());</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Returns a comparator that compares &#123;<span class="doctag">@link</span> Map.Entry&#125; by key using the given</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> &lt;K, V&gt; Comparator&lt;Map.Entry&lt;K, V&gt;&gt; comparingByKey(Comparator&lt;? <span class="keyword">super</span> K&gt; cmp) &#123;</span><br><span class="line">        Objects.requireNonNull(cmp);</span><br><span class="line">        <span class="keyword">return</span> (Comparator&lt;Map.Entry&lt;K, V&gt;&gt; &amp; Serializable)</span><br><span class="line">            (c1, c2) -&gt; cmp.compare(c1.getKey(), c2.getKey());</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Returns a comparator that compares &#123;<span class="doctag">@link</span> Map.Entry&#125; by value using the given</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> &lt;K, V&gt; Comparator&lt;Map.Entry&lt;K, V&gt;&gt; comparingByValue(Comparator&lt;? <span class="keyword">super</span> V&gt; cmp) &#123;</span><br><span class="line">        Objects.requireNonNull(cmp);</span><br><span class="line">        <span class="keyword">return</span> (Comparator&lt;Map.Entry&lt;K, V&gt;&gt; &amp; Serializable)</span><br><span class="line">            (c1, c2) -&gt; cmp.compare(c1.getValue(), c2.getValue());</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>根据Set和Collection的特性得知，key和entry都是没有重复的，值可以重复。键与值都可以为null。</p>
<p>以下都是我们在Map的子类中经常用到的，或者知道的但不一定用过的。不需要过多的解释了。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Returns the number of key-value mappings in this map.  </span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> the number of key-value mappings in this map</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">size</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Returns &lt;tt&gt;true&lt;/tt&gt; if this map contains no key-value mappings.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> &lt;tt&gt;true&lt;/tt&gt; if this map contains no key-value mappings</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">boolean</span> <span class="title">isEmpty</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Returns &lt;tt&gt;true&lt;/tt&gt; if this map contains a mapping for the specified</span></span><br><span class="line"><span class="comment"> * key.  </span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">boolean</span> <span class="title">containsKey</span><span class="params">(Object key)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Returns &lt;tt&gt;true&lt;/tt&gt; if this map maps one or more keys to the</span></span><br><span class="line"><span class="comment"> * specified value.  </span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">boolean</span> <span class="title">containsValue</span><span class="params">(Object value)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Returns the value to which the specified key is mapped,</span></span><br><span class="line"><span class="comment"> * or &#123;<span class="doctag">@code</span> null&#125; if this map contains no mapping for the key.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function">V <span class="title">get</span><span class="params">(Object key)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// Modification Operations</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Associates the specified value with the specified key in this map</span></span><br><span class="line"><span class="comment"> * (optional operation).  </span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function">V <span class="title">put</span><span class="params">(K key, V value)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Removes the mapping for a key from this map if it is present</span></span><br><span class="line"><span class="comment"> * (optional operation).   </span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function">V <span class="title">remove</span><span class="params">(Object key)</span></span>;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// Bulk Operations</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Copies all of the mappings from the specified map to this map</span></span><br><span class="line"><span class="comment"> * (optional operation).  </span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">putAll</span><span class="params">(Map&lt;? extends K, ? extends V&gt; m)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Removes all of the mappings from this map (optional operation).</span></span><br><span class="line"><span class="comment"> * The map will be empty after this call returns.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@throws</span> UnsupportedOperationException if the &lt;tt&gt;clear&lt;/tt&gt; operation</span></span><br><span class="line"><span class="comment"> *         is not supported by this map</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">clear</span><span class="params">()</span></span>;</span><br></pre></td></tr></table></figure>



<p>一下是Map的子类或子类的子类的声明方式，至于这里为什么使用Map这个大父类来声明而不是使用自己的类名来声明，是因为这样可以使用Map或父类的方法。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//Map的子类或子类的子类</span></span><br><span class="line">Map&lt;Integer,String&gt; m1 = <span class="keyword">new</span> HashMap&lt;&gt;();</span><br><span class="line"></span><br><span class="line">Map&lt;Integer,String&gt; m2 = <span class="keyword">new</span> TreeMap&lt;&gt;();</span><br><span class="line"></span><br><span class="line">Map&lt;Integer,String&gt; m3 = <span class="keyword">new</span> LinkedHashMap&lt;&gt;();</span><br><span class="line"></span><br><span class="line">Map&lt;Integer,String&gt; m4 = <span class="keyword">new</span> Hashtable&lt;&gt;();</span><br><span class="line"></span><br><span class="line">Map&lt;Integer,String&gt; m5 = <span class="keyword">new</span> ConcurrentHashMap&lt;&gt;();</span><br></pre></td></tr></table></figure>

<p>但是Map是如何实现以键值对存储数据的呢？这么做又有什么好处和坏处呢</p>
<h4 id="实现"><a href="#实现" class="headerlink" title="实现"></a>实现</h4><p>通过源码得知，Map是三个集合的共同体现。通过没有重复的键（因为键具有互异性）与可重复的值映射完成Map的设计，这实际就是将键作为数组，数组中存储引用的对象。通常情况下，Map不具备有序性（TreeMap除外）。</p>
<p>Map主要包括HashMap和LinkedHashMap,TreeMap，也是我们主要需要了解与掌握的类。以及需要了解以及会使用的Tree Map和Concurrent Hash Map类。</p>
<h4 id="Hash-Map"><a href="#Hash-Map" class="headerlink" title="Hash Map"></a>Hash Map</h4><p>Hash Map是不能有序输出的，即不能按照插入的顺序输出，输出顺序可能是无序的。</p>
<p>你会发现在Map中有很多Hash，那么什么是Hash呢？</p>
<h5 id="Hash"><a href="#Hash" class="headerlink" title="Hash"></a>Hash</h5><h6 id="什么是Hash？"><a href="#什么是Hash？" class="headerlink" title="什么是Hash？"></a>什么是Hash？</h6><p>Hash又称哈希，散列，是一种算法。实现是通过输入任意长度的值，通过哈希算法变成固定长度的输出，这个由<strong>任意长度的输入</strong>到<strong>固定长度的输出</strong>的<strong>映射规则</strong>就是hash算法。</p>
<h6 id="hash的特点"><a href="#hash的特点" class="headerlink" title="hash的特点"></a>hash的特点</h6><ul>
<li>不可逆，即根据算出的hash值不能得到原始数据</li>
<li>散列，数据要足够分散，这也是他叫散列的原因</li>
</ul>
<p>再好的算法，在数据基数非常大的前提下也会变得不堪一击，再好的散列，遇到足够多的数据也会不那么散列，此时就会出现冲突碰撞的情况，那么如何解决冲突与碰撞就成了新的问题。</p>
<h6 id="冲突的产生"><a href="#冲突的产生" class="headerlink" title="冲突的产生"></a>冲突的产生</h6><ul>
<li>数据量大</li>
<li>散列范围小</li>
</ul>
<h6 id="解决冲突的方法"><a href="#解决冲突的方法" class="headerlink" title="解决冲突的方法"></a>解决冲突的方法</h6><p>hash算法是一定会有冲突的，那么如果我们如果遇到了hash冲突需要解决的时候应该怎么处理呢？比较常用的算法是<strong>链地址法</strong>和<strong>开放地址法</strong>。</p>
<ul>
<li><p>链地址法，也叫拉链法，实现原理是将冲突的数据像糖葫芦一样串起来，即当遇到冲突时，将产生冲突的数据连接到hash值相同的数据最后面，形成链表。</p>
</li>
<li><p>开放地址法，也叫开放寻址法，包括线性探测法，二次hash，双重散列法。开放寻址法实现原理是当产生冲突时，往下寻找空地址并将数据放入其中。</p>
</li>
</ul>
<p>具体有关Hash的讲解可参考：<a target="_blank" rel="noopener" href="https://blog.csdn.net/woshimaxiao1/article/details/83661464">https://blog.csdn.net/woshimaxiao1/article/details/83661464</a></p>
<p>我们知道了Hash的原理之后，再来看由此而生的HashMap,HashMap主要包括两部分，数组和链表，数组是HashMap的主体，链表则是为了解决冲突而存在的（JDK1.8）。</p>
<h5 id="常量"><a href="#常量" class="headerlink" title="常量"></a>常量</h5><p>下面我们来深入探究一下，Hash Map的内部到底是什么样的吧。</p>
<p>首先从类的定义中我们可以看到他继承自AbstractMap，实现了Map，Cloneable，Serializable三个接口，这三个接口中Map是我们刚才看到的，Cloneable是我们之前用到的，至于Serializable是什么意思吗，就是对象序列化的接口，只有实现了这个接口，它的对象才能被序列化，至于具体的作用可以参考这篇文章：<a target="_blank" rel="noopener" href="https://baijiahao.baidu.com/s?id=1633305649182361563&amp;wfr=spider&amp;for=pc">https://baijiahao.baidu.com/s?id=1633305649182361563&amp;wfr=spider&amp;for=pc</a> 。 </p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">HashMap</span>&lt;<span class="title">K</span>,<span class="title">V</span>&gt; <span class="keyword">extends</span> <span class="title">AbstractMap</span>&lt;<span class="title">K</span>,<span class="title">V</span>&gt;</span></span><br><span class="line"><span class="class">    <span class="keyword">implements</span> <span class="title">Map</span>&lt;<span class="title">K</span>,<span class="title">V</span>&gt;, <span class="title">Cloneable</span>, <span class="title">Serializable</span> </span>&#123;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">//这是她的序列化标识，被transient关键字所标记的变量与方法不会被序列化，序列化时为了能高效快捷的存储在存储介质上，</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">long</span> serialVersionUID = <span class="number">362498820763181265L</span>;</span><br></pre></td></tr></table></figure>

<p>在这里它定义了很多常量，我们来看一下。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * The default initial capacity - MUST be a power of two.</span></span><br><span class="line"><span class="comment"> * 初始化容量默认是1的二进制向左移四位。1的二进制是00000001，向左移四位变成00010000，等于16</span></span><br><span class="line"><span class="comment"> * 初始容量不大不小，刚刚合适，太大的话很占空间，太小的话，又容易导致空间不够二直接进行扩容</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> DEFAULT_INITIAL_CAPACITY = <span class="number">1</span> &lt;&lt; <span class="number">4</span>; <span class="comment">// aka 16</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * The maximum capacity, used if a higher value is implicitly specified</span></span><br><span class="line"><span class="comment"> * by either of the constructors with arguments.</span></span><br><span class="line"><span class="comment"> * MUST be a power of two &lt;= 1&lt;&lt;30.</span></span><br><span class="line"><span class="comment"> * 最大容量：1的二进制向左移30位，00000000 00000000 00000000 00000001</span></span><br><span class="line"><span class="comment"> * 							 01000000 00000000 00000000 00000000 = 1 073 741 824</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> MAXIMUM_CAPACITY = <span class="number">1</span> &lt;&lt; <span class="number">30</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * The load factor used when none specified in constructor.</span></span><br><span class="line"><span class="comment"> * 加载因子：用于控制剩余空间，比如你需要8个空间，他就会给你8/0.75 = 11个空间</span></span><br><span class="line"><span class="comment"> * 加载因子设为0.75是有原因的，设置的太小的化，剩余空间太多容易造成浪费，设置的太大的话，又容易导致</span></span><br><span class="line"><span class="comment"> * 复制的时候速度很慢</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">float</span> DEFAULT_LOAD_FACTOR = <span class="number">0.75f</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * The bin count threshold for using a tree rather than list for a</span></span><br><span class="line"><span class="comment"> * bin.  Bins are converted to trees when adding an element to a</span></span><br><span class="line"><span class="comment"> * bin with at least this many nodes. The value must be greater</span></span><br><span class="line"><span class="comment"> * than 2 and should be at least 8 to mesh with assumptions in</span></span><br><span class="line"><span class="comment"> * tree removal about conversion back to plain bins upon</span></span><br><span class="line"><span class="comment"> * shrinkage.</span></span><br><span class="line"><span class="comment"> * 这个是Java8中的最大更新点，将hashmap的数据结构由【数组+链表】变成了【数组+链表+红黑树】</span></span><br><span class="line"><span class="comment"> * 这个就是判断该条链表是否需要树化的判断条件，当链表中元素&gt;=8时会树化，</span></span><br><span class="line"><span class="comment"> * 至于为什么是8，这个网上的答案一艘一大篓，</span></span><br><span class="line"><span class="comment"> * https://blog.csdn.net/F1004145107/article/details/105904975/</span></span><br><span class="line"><span class="comment"> * 可以看看这篇</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> TREEIFY_THRESHOLD = <span class="number">8</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * The bin count threshold for untreeifying a (split) bin during a</span></span><br><span class="line"><span class="comment"> * resize operation. Should be less than TREEIFY_THRESHOLD, and at</span></span><br><span class="line"><span class="comment"> * most 6 to mesh with shrinkage detection under removal.</span></span><br><span class="line"><span class="comment"> * 这个就跟上面树化是相反的了，当链表中的元素&lt;=6时，就会变成普通链表</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> UNTREEIFY_THRESHOLD = <span class="number">6</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * The smallest table capacity for which bins may be treeified.</span></span><br><span class="line"><span class="comment"> * (Otherwise the table is resized if too many nodes in a bin.)</span></span><br><span class="line"><span class="comment"> * Should be at least 4 * TREEIFY_THRESHOLD to avoid conflicts</span></span><br><span class="line"><span class="comment"> * between resizing and treeification thresholds.</span></span><br><span class="line"><span class="comment"> * 红黑树化所需的最小容量，即当数据总量小于64的时候就算一个节点上的数据超过8条都不会树化</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> MIN_TREEIFY_CAPACITY = <span class="number">64</span>;</span><br></pre></td></tr></table></figure>

<h5 id="构造函数"><a href="#构造函数" class="headerlink" title="构造函数"></a>构造函数</h5><p>Hash Map一共有四个构造函数，来看源码</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//带参数，初始化容量与加载因子，</span></span><br><span class="line"><span class="comment">//Map&lt;Integer,String&gt; m = new HashMap&lt;&gt;(10,0.6f);</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">HashMap</span><span class="params">(<span class="keyword">int</span> initialCapacity, <span class="keyword">float</span> loadFactor)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (initialCapacity &lt; <span class="number">0</span>)</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException(<span class="string">&quot;Illegal initial capacity: &quot;</span> +</span><br><span class="line">                                           initialCapacity);</span><br><span class="line">    <span class="keyword">if</span> (initialCapacity &gt; MAXIMUM_CAPACITY)</span><br><span class="line">        initialCapacity = MAXIMUM_CAPACITY;</span><br><span class="line">    <span class="keyword">if</span> (loadFactor &lt;= <span class="number">0</span> || Float.isNaN(loadFactor))</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException(<span class="string">&quot;Illegal load factor: &quot;</span> +</span><br><span class="line">                                           loadFactor);</span><br><span class="line">    <span class="keyword">this</span>.loadFactor = loadFactor;</span><br><span class="line">    <span class="comment">//在这里，这个threshold是有什么用的呢？，我们来看一下tableSizeFor这个函数干了什么</span></span><br><span class="line">    <span class="keyword">this</span>.threshold = tableSizeFor(initialCapacity);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//Returns a power of two size for the given target capacity.</span></span><br><span class="line"><span class="comment">//官方注释：返回一个提供的容量的两倍容量，就是说你传一个10的话，他就返回20，</span></span><br><span class="line"> <span class="function"><span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> <span class="title">tableSizeFor</span><span class="params">(<span class="keyword">int</span> cap)</span> </span>&#123;</span><br><span class="line">     <span class="keyword">int</span> n = cap - <span class="number">1</span>;</span><br><span class="line">     n |= n &gt;&gt;&gt; <span class="number">1</span>;</span><br><span class="line">     n |= n &gt;&gt;&gt; <span class="number">2</span>;</span><br><span class="line">     n |= n &gt;&gt;&gt; <span class="number">4</span>;</span><br><span class="line">     n |= n &gt;&gt;&gt; <span class="number">8</span>;</span><br><span class="line">     n |= n &gt;&gt;&gt; <span class="number">16</span>;</span><br><span class="line">     <span class="comment">//这里还设置了一个判断防止返回的值为负数或者0</span></span><br><span class="line">     <span class="keyword">return</span> (n &lt; <span class="number">0</span>) ? <span class="number">1</span> : (n &gt;= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + <span class="number">1</span>;</span><br><span class="line"> &#125;</span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Constructs an empty &lt;tt&gt;HashMap&lt;/tt&gt; with the specified initial</span></span><br><span class="line"><span class="comment"> * capacity and the default load factor (0.75).</span></span><br><span class="line"><span class="comment"> * 只有初始化容量的构造函数</span></span><br><span class="line"><span class="comment"> * Map&lt;Integer,String&gt; m1 = new HashMap&lt;&gt;(10);</span></span><br><span class="line"><span class="comment"> * 从代码中可以看出，调用此函数时系统会默认分配默认的加载因子，同时调用上一个构造函数</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">HashMap</span><span class="params">(<span class="keyword">int</span> initialCapacity)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">this</span>(initialCapacity, DEFAULT_LOAD_FACTOR);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Constructs an empty &lt;tt&gt;HashMap&lt;/tt&gt; with the default initial capacity</span></span><br><span class="line"><span class="comment"> * (16) and the default load factor (0.75).</span></span><br><span class="line"><span class="comment"> * 无参，全部为默认的参数</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">HashMap</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">this</span>.loadFactor = DEFAULT_LOAD_FACTOR; <span class="comment">// all other fields defaulted</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Constructs a new &lt;tt&gt;HashMap&lt;/tt&gt; with the same mappings as the</span></span><br><span class="line"><span class="comment"> * specified &lt;tt&gt;Map&lt;/tt&gt;.  The &lt;tt&gt;HashMap&lt;/tt&gt; is created with</span></span><br><span class="line"><span class="comment"> * default load factor (0.75) and an initial capacity sufficient to</span></span><br><span class="line"><span class="comment"> * hold the mappings in the specified &lt;tt&gt;Map&lt;/tt&gt;.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span>   m the map whose mappings are to be placed in this map</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@throws</span>  NullPointerException if the specified map is null</span></span><br><span class="line"><span class="comment"> * 此构造函数未copy函数，即copy传进来的参数的结构与数据，只要是Map的子类或者子类的子类就可以</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">HashMap</span><span class="params">(Map&lt;? extends K, ? extends V&gt; m)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">this</span>.loadFactor = DEFAULT_LOAD_FACTOR;</span><br><span class="line">    putMapEntries(m, <span class="keyword">false</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h5 id="初始化"><a href="#初始化" class="headerlink" title="初始化"></a>初始化</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line">Map&lt;Integer,String&gt; m1 = <span class="keyword">new</span> HashMap&lt;&gt;(<span class="number">10</span>);<span class="comment">//设置初始化容量为10</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//首先进入classloader函数，这个之后再说，</span></span><br><span class="line"><span class="comment">//其次进入，带一个参数的hashmap构造函数HashMap(int initialCapacity)</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">HashMap</span><span class="params">(<span class="keyword">int</span> initialCapacity)</span> </span>&#123;</span><br><span class="line">    <span class="comment">//这个函数调用带两个参数的构造函数HashMap(int initialCapacity, float loadFactor)</span></span><br><span class="line">    <span class="keyword">this</span>(initialCapacity, DEFAULT_LOAD_FACTOR);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">HashMap</span><span class="params">(<span class="keyword">int</span> initialCapacity, <span class="keyword">float</span> loadFactor)</span> </span>&#123;</span><br><span class="line">    <span class="comment">//当初始化容量小于0，抛出异常</span></span><br><span class="line">    <span class="keyword">if</span> (initialCapacity &lt; <span class="number">0</span>)</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException(<span class="string">&quot;Illegal initial capacity: &quot;</span> +</span><br><span class="line">                                           initialCapacity);</span><br><span class="line">    <span class="comment">//当初始化容量大于大于最大容量时，将他限制在最大容量</span></span><br><span class="line">    <span class="keyword">if</span> (initialCapacity &gt; MAXIMUM_CAPACITY)</span><br><span class="line">        initialCapacity = MAXIMUM_CAPACITY;</span><br><span class="line">    <span class="comment">//当加载因子小于0，抛出异常</span></span><br><span class="line">    <span class="keyword">if</span> (loadFactor &lt;= <span class="number">0</span> || Float.isNaN(loadFactor))</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException(<span class="string">&quot;Illegal load factor: &quot;</span> +</span><br><span class="line">                                           loadFactor);</span><br><span class="line">    <span class="comment">//加载因子赋值</span></span><br><span class="line">    <span class="keyword">this</span>.loadFactor = loadFactor;</span><br><span class="line">    <span class="comment">//根据初始化容量设置threshold，这里threshold不是容量，是下一次更新容量要设置的容量</span></span><br><span class="line">    <span class="keyword">this</span>.threshold = tableSizeFor(initialCapacity);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//设置threshold</span></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> <span class="title">tableSizeFor</span><span class="params">(<span class="keyword">int</span> cap)</span> </span>&#123;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">int</span> n = cap - <span class="number">1</span>;<span class="comment">//10-1=9，二进制为：1001</span></span><br><span class="line">    <span class="comment">//&gt;&gt;&gt;代表无符号右移运算，|= 代表 +=</span></span><br><span class="line">    n |= n &gt;&gt;&gt; <span class="number">1</span>;<span class="comment">//n &gt;&gt;&gt; 1 = 4，转换成二进制为：0100，1001 | 0100=1101=13=n</span></span><br><span class="line">    n |= n &gt;&gt;&gt; <span class="number">2</span>;<span class="comment">//n &gt;&gt;&gt; 2 = 0011=3，0011 | 1101 = 1111 = 15</span></span><br><span class="line">    n |= n &gt;&gt;&gt; <span class="number">4</span>;<span class="comment">//根据‘|’的运算特性，下面在运算都只会是1111，</span></span><br><span class="line">    n |= n &gt;&gt;&gt; <span class="number">8</span>;</span><br><span class="line">    n |= n &gt;&gt;&gt; <span class="number">16</span>;</span><br><span class="line">    <span class="comment">//到此n=15，下面这句话是n小于0则返回1，否则返回(n &gt;= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1，</span></span><br><span class="line">    <span class="comment">//所以最后返回n+1=16，</span></span><br><span class="line">    <span class="keyword">return</span> (n &lt; <span class="number">0</span>) ? <span class="number">1</span> : (n &gt;= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + <span class="number">1</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//至此，初始化完成。</span></span><br></pre></td></tr></table></figure>

<h5 id="put（K，V）"><a href="#put（K，V）" class="headerlink" title="put（K，V）"></a>put（K，V）</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> V <span class="title">put</span><span class="params">(K key, V value)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> putVal(hash(key), key, value, <span class="keyword">false</span>, <span class="keyword">true</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//hash：key的hash值</span></span><br><span class="line"><span class="comment">//onlyIfAbsent：当为真时，不改变已存在的数据</span></span><br><span class="line"><span class="comment">//evict：当初始化的时候是false，这里传入的是true说明不是初始化，</span></span><br><span class="line"><span class="function"><span class="keyword">final</span> V <span class="title">putVal</span><span class="params">(<span class="keyword">int</span> hash, K key, V value, <span class="keyword">boolean</span> onlyIfAbsent,</span></span></span><br><span class="line"><span class="params"><span class="function">                   <span class="keyword">boolean</span> evict)</span> </span>&#123;</span><br><span class="line">    Node&lt;K,V&gt;[] tab; Node&lt;K,V&gt; p; <span class="keyword">int</span> n, i;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">//第一次put，成立并且为tab与n赋值</span></span><br><span class="line">    <span class="keyword">if</span> ((tab = table) == <span class="keyword">null</span> || (n = tab.length) == <span class="number">0</span>)</span><br><span class="line">        n = (tab = resize()).length;</span><br><span class="line">    <span class="comment">//这里是判断是否是第一次put,并且为p赋值，下面会用到这个</span></span><br><span class="line">    <span class="comment">//(n - 1) &amp; hash：这个值等于hash，至于为什么会这样，因为n是2的n次方，这样n-1的二进制就全是1，通过&amp;运算，就会得到的值等于hash，</span></span><br><span class="line">    <span class="keyword">if</span> ((p = tab[i = (n - <span class="number">1</span>) &amp; hash]) == <span class="keyword">null</span>)</span><br><span class="line">        tab[i] = newNode(hash, key, value, <span class="keyword">null</span>);</span><br><span class="line">    <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="comment">//进入这的都是hash值相同，需要成链的数据</span></span><br><span class="line">        Node&lt;K,V&gt; e; K k;</span><br><span class="line">        <span class="keyword">if</span> (p.hash == hash &amp;&amp;</span><br><span class="line">            ((k = p.key) == key || (key != <span class="keyword">null</span> &amp;&amp; key.equals(k))))</span><br><span class="line">            <span class="comment">//key值相同，覆盖</span></span><br><span class="line">            e = p;</span><br><span class="line">        <span class="keyword">else</span> <span class="keyword">if</span> (p <span class="keyword">instanceof</span> TreeNode)</span><br><span class="line">            e = ((TreeNode&lt;K,V&gt;)p).putTreeVal(<span class="keyword">this</span>, tab, hash, key, value);</span><br><span class="line">        <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="comment">//循环，注意这里是从第一个节点开始</span></span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">int</span> binCount = <span class="number">0</span>; ; ++binCount) &#123;</span><br><span class="line">                <span class="comment">//这里p是hash值等于hash的节点的</span></span><br><span class="line">                <span class="keyword">if</span> ((e = p.next) == <span class="keyword">null</span>) &#123;</span><br><span class="line">                    <span class="comment">//将新节点设置为上一节点的下一节点，即尾插，这也是java8的新特点之一</span></span><br><span class="line">                    p.next = newNode(hash, key, value, <span class="keyword">null</span>);</span><br><span class="line">                    <span class="comment">//红黑树化</span></span><br><span class="line">                    <span class="keyword">if</span> (binCount &gt;= TREEIFY_THRESHOLD - <span class="number">1</span>) <span class="comment">// -1 for 1st</span></span><br><span class="line">                        treeifyBin(tab, hash);</span><br><span class="line">                    <span class="keyword">break</span>;</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="comment">//暂时想不到这里是在预防什么</span></span><br><span class="line">                <span class="keyword">if</span> (e.hash == hash &amp;&amp;</span><br><span class="line">                    ((k = e.key) == key || (key != <span class="keyword">null</span> &amp;&amp; key.equals(k))))</span><br><span class="line">                    <span class="keyword">break</span>;</span><br><span class="line">                p = e;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (e != <span class="keyword">null</span>) &#123; <span class="comment">// existing mapping for key</span></span><br><span class="line">            V oldValue = e.value;</span><br><span class="line">            <span class="keyword">if</span> (!onlyIfAbsent || oldValue == <span class="keyword">null</span>)</span><br><span class="line">                e.value = value;</span><br><span class="line">            afterNodeAccess(e);</span><br><span class="line">            <span class="keyword">return</span> oldValue;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    ++modCount;</span><br><span class="line">    <span class="keyword">if</span> (++size &gt; threshold)</span><br><span class="line">        resize();</span><br><span class="line">    afterNodeInsertion(evict);</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h5 id="扩容"><a href="#扩容" class="headerlink" title="扩容"></a>扩容</h5><p>HashMap扩容，到这里我已经没有场外援助了，他们大多都是以老版Java为例讲的扩容，到这里我只能孤军奋战了，不过也是时候检验一下我的成果了。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">final</span> Node&lt;K,V&gt;[] resize() &#123;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">//首先，不像Java7,java7中传入了上一个table的容量</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">//声明一个节点来接收旧的hashmap的数据表</span></span><br><span class="line">    Node&lt;K,V&gt;[] oldTab = table;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">int</span> oldCap = (oldTab == <span class="keyword">null</span>) ? <span class="number">0</span> : oldTab.length;</span><br><span class="line">    <span class="comment">//旧表的下一个容量，就是旧表要更新时需要设置的容量</span></span><br><span class="line">    <span class="keyword">int</span> oldThr = threshold;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">//声明新的</span></span><br><span class="line">    <span class="keyword">int</span> newCap, newThr = <span class="number">0</span>;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">//oldCap是旧容量的长度</span></span><br><span class="line">    <span class="keyword">if</span> (oldCap &gt; <span class="number">0</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (oldCap &gt;= MAXIMUM_CAPACITY) &#123;</span><br><span class="line">            <span class="comment">//这里由于旧表容量已经非常接近int类型的极限，所以这里只能返回int的最大值</span></span><br><span class="line">            threshold = Integer.MAX_VALUE;</span><br><span class="line">            <span class="keyword">return</span> oldTab;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//这里是判断新的容量不大于设置的最大容量，旧的容量大于默认初始化容量</span></span><br><span class="line">        <span class="keyword">else</span> <span class="keyword">if</span> ((newCap = oldCap &lt;&lt; <span class="number">1</span>) &lt; MAXIMUM_CAPACITY &amp;&amp;</span><br><span class="line">                 oldCap &gt;= DEFAULT_INITIAL_CAPACITY)</span><br><span class="line">            <span class="comment">//箭头向左，左移运算，乘以2，容量扩大一倍，</span></span><br><span class="line">            newThr = oldThr &lt;&lt; <span class="number">1</span>; <span class="comment">// double threshold</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//oldThr是旧容量的下一个容量，即二倍的他，上面有提到过，下面这两个都很简单</span></span><br><span class="line">    <span class="comment">//判断条件之后再说</span></span><br><span class="line">    <span class="keyword">else</span> <span class="keyword">if</span> (oldThr &gt; <span class="number">0</span>) <span class="comment">// initial capacity was placed in threshold</span></span><br><span class="line">        newCap = oldThr;</span><br><span class="line">    <span class="keyword">else</span> &#123;               <span class="comment">// zero initial threshold signifies using defaults</span></span><br><span class="line">        newCap = DEFAULT_INITIAL_CAPACITY;</span><br><span class="line">        newThr = (<span class="keyword">int</span>)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//这里是初始化时才会用到，在这里用不到</span></span><br><span class="line">    <span class="keyword">if</span> (newThr == <span class="number">0</span>) &#123;</span><br><span class="line">        <span class="keyword">float</span> ft = (<span class="keyword">float</span>)newCap * loadFactor;</span><br><span class="line">        newThr = (newCap &lt; MAXIMUM_CAPACITY &amp;&amp; ft &lt; (<span class="keyword">float</span>)MAXIMUM_CAPACITY ?</span><br><span class="line">                  (<span class="keyword">int</span>)ft : Integer.MAX_VALUE);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">//最终在多种情况下，判断出合适的情况为threshold赋值</span></span><br><span class="line">    threshold = newThr;</span><br><span class="line">    </span><br><span class="line">    </span><br><span class="line">    <span class="comment">//clone的过程，有兴趣的同学可以看一下</span></span><br><span class="line">    <span class="meta">@SuppressWarnings(&#123;&quot;rawtypes&quot;,&quot;unchecked&quot;&#125;)</span></span><br><span class="line">    Node&lt;K,V&gt;[] newTab = (Node&lt;K,V&gt;[])<span class="keyword">new</span> Node[newCap];</span><br><span class="line">    table = newTab;</span><br><span class="line">    <span class="comment">//下面就是将旧的数据一个一个复制到新的map中，</span></span><br><span class="line">    <span class="keyword">if</span> (oldTab != <span class="keyword">null</span>) &#123;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> j = <span class="number">0</span>; j &lt; oldCap; ++j) &#123;</span><br><span class="line">            Node&lt;K,V&gt; e;</span><br><span class="line">            <span class="keyword">if</span> ((e = oldTab[j]) != <span class="keyword">null</span>) &#123;</span><br><span class="line">                oldTab[j] = <span class="keyword">null</span>;</span><br><span class="line">                <span class="keyword">if</span> (e.next == <span class="keyword">null</span>)</span><br><span class="line">                    newTab[e.hash &amp; (newCap - <span class="number">1</span>)] = e;</span><br><span class="line">                <span class="keyword">else</span> <span class="keyword">if</span> (e <span class="keyword">instanceof</span> TreeNode)</span><br><span class="line">                    ((TreeNode&lt;K,V&gt;)e).split(<span class="keyword">this</span>, newTab, j, oldCap);</span><br><span class="line">                <span class="keyword">else</span> &#123; <span class="comment">// preserve order</span></span><br><span class="line">                    Node&lt;K,V&gt; loHead = <span class="keyword">null</span>, loTail = <span class="keyword">null</span>;</span><br><span class="line">                    Node&lt;K,V&gt; hiHead = <span class="keyword">null</span>, hiTail = <span class="keyword">null</span>;</span><br><span class="line">                    Node&lt;K,V&gt; next;</span><br><span class="line">                    <span class="keyword">do</span> &#123;</span><br><span class="line">                        next = e.next;</span><br><span class="line">                        <span class="keyword">if</span> ((e.hash &amp; oldCap) == <span class="number">0</span>) &#123;</span><br><span class="line">                            <span class="keyword">if</span> (loTail == <span class="keyword">null</span>)</span><br><span class="line">                                loHead = e;</span><br><span class="line">                            <span class="keyword">else</span></span><br><span class="line">                                loTail.next = e;</span><br><span class="line">                            loTail = e;</span><br><span class="line">                        &#125;</span><br><span class="line">                        <span class="keyword">else</span> &#123;</span><br><span class="line">                            <span class="keyword">if</span> (hiTail == <span class="keyword">null</span>)</span><br><span class="line">                                hiHead = e;</span><br><span class="line">                            <span class="keyword">else</span></span><br><span class="line">                                hiTail.next = e;</span><br><span class="line">                            hiTail = e;</span><br><span class="line">                        &#125;</span><br><span class="line">                    &#125; <span class="keyword">while</span> ((e = next) != <span class="keyword">null</span>);</span><br><span class="line">                    <span class="keyword">if</span> (loTail != <span class="keyword">null</span>) &#123;</span><br><span class="line">                        loTail.next = <span class="keyword">null</span>;</span><br><span class="line">                        newTab[j] = loHead;</span><br><span class="line">                    &#125;</span><br><span class="line">                    <span class="keyword">if</span> (hiTail != <span class="keyword">null</span>) &#123;</span><br><span class="line">                        hiTail.next = <span class="keyword">null</span>;</span><br><span class="line">                        newTab[j + oldCap] = hiHead;</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> newTab;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>那什么时候才会调用resize()方法呢？在我们的容量等于threshold这个值的时候就会进行扩容，此时在putVal的最后会判断（++size）的值是否大于threshold，如果是的话就调用扩容函数。</p>
<ul>
<li>putMapEntries</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//</span></span><br><span class="line"><span class="function"><span class="keyword">final</span> <span class="keyword">void</span> <span class="title">putMapEntries</span><span class="params">(Map&lt;? extends K, ? extends V&gt; m, <span class="keyword">boolean</span> evict)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">int</span> s = m.size();</span><br><span class="line">    <span class="keyword">if</span> (s &gt; <span class="number">0</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (table == <span class="keyword">null</span>) &#123; <span class="comment">// pre-size</span></span><br><span class="line">            <span class="keyword">float</span> ft = ((<span class="keyword">float</span>)s / loadFactor) + <span class="number">1.0F</span>;</span><br><span class="line">            <span class="keyword">int</span> t = ((ft &lt; (<span class="keyword">float</span>)MAXIMUM_CAPACITY) ?</span><br><span class="line">                     (<span class="keyword">int</span>)ft : MAXIMUM_CAPACITY);</span><br><span class="line">            <span class="keyword">if</span> (t &gt; threshold)</span><br><span class="line">                threshold = tableSizeFor(t);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">else</span> <span class="keyword">if</span> (s &gt; threshold)</span><br><span class="line">            <span class="comment">//当要克隆的数据量大于</span></span><br><span class="line">            resize();<span class="comment">//这里</span></span><br><span class="line">        <span class="keyword">for</span> (Map.Entry&lt;? extends K, ? extends V&gt; e : m.entrySet()) &#123;</span><br><span class="line">            K key = e.getKey();</span><br><span class="line">            V value = e.getValue();</span><br><span class="line">            putVal(hash(key), key, value, <span class="keyword">false</span>, evict);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//当我们需要clone一个map的时候才会调用这个函数，一共有三个调用这个函数地方，都是clone一个map</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">HashMap</span><span class="params">(Map&lt;? extends K, ? extends V&gt; m)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">this</span>.loadFactor = DEFAULT_LOAD_FACTOR;</span><br><span class="line">    putMapEntries(m, <span class="keyword">false</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>在Java8中，可以看到的改变就是增加了红黑树来提升查询效率，再就是将链表的插入改成了尾插法。</p>
<p>至于Java8为什么不适用头插法的原因之一是因为头插会造成链表死链，参考：<a target="_blank" rel="noopener" href="https://blog.csdn.net/chenyiminnanjing/article/details/82706942">https://blog.csdn.net/chenyiminnanjing/article/details/82706942</a> 。原因之二是因为Java7使用头插是考虑到了热点数据的点（最后插入的数据更早用到），但是因为扩容机制的原因，会导致排序失去作用，所以自然这点也就没有用了。</p>
<p>以上就是关于Hash Map的个人理解（部分）了，走了一遍源码，还是有很多地方没走到，但是对于Hash Map有了一个很大了解，下一步就是了解她的红黑树结构，先去了解什么是红黑树吧，最后来看源码会轻松很多。</p>
<p><strong>性能表现</strong>：</p>
<p>由于是以数组为主体，所以查询很快，但是增删慢。但是具体情况视具体情况而定。只能说数组在查询上非常有优势，因为是下标查询，时间复杂度为O（1），Hash Map本身是个K-V的数组，但是为了解决各种冲突演变成了K-V数组+链表的结构，而链表又具有增删快速的特性，所以综上来看的话，以数组为主，查询快，在主体上增删数据较慢，在链表上增删较快，查询较慢。</p>
<h4 id="Linked-Hash-Map"><a href="#Linked-Hash-Map" class="headerlink" title="Linked Hash Map"></a>Linked Hash Map</h4><p>Linked Hash Map是一个以双向链表。LinkedHashMap=HashMap+双向链表，实现双向链表是为了记录节点的插入顺序，这样就可以实现有序插入和输出。</p>
<p>更多详情参考：<a target="_blank" rel="noopener" href="https://zhuanlan.zhihu.com/p/34490361">https://zhuanlan.zhihu.com/p/34490361</a> 。</p>
<p>看一下Linked Hash Map的源码，继承自Hash Map，实现了Map类。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">LinkedHashMap</span>&lt;<span class="title">K</span>,<span class="title">V</span>&gt;</span></span><br><span class="line"><span class="class">    <span class="keyword">extends</span> <span class="title">HashMap</span>&lt;<span class="title">K</span>,<span class="title">V</span>&gt;</span></span><br><span class="line"><span class="class">    <span class="keyword">implements</span> <span class="title">Map</span>&lt;<span class="title">K</span>,<span class="title">V</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>看如下代码，Linked Hash Map为了实现双向链表写了哪些代码吧</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//首先就是这个entry，它继承自Hash Map的Node类，又自带两个前后节点，在Hash Map中他只有一个next的节点</span></span><br><span class="line"><span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Entry</span>&lt;<span class="title">K</span>,<span class="title">V</span>&gt; <span class="keyword">extends</span> <span class="title">HashMap</span>.<span class="title">Node</span>&lt;<span class="title">K</span>,<span class="title">V</span>&gt; </span>&#123;</span><br><span class="line">    Entry&lt;K,V&gt; before, after;</span><br><span class="line">    Entry(<span class="keyword">int</span> hash, K key, V value, Node&lt;K,V&gt; next) &#123;</span><br><span class="line">        <span class="keyword">super</span>(hash, key, value, next);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//其次</span></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * The head (eldest) of the doubly linked list.</span></span><br><span class="line"><span class="comment"> * 头部，最先被插入的节点，</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">transient</span> LinkedHashMap.Entry&lt;K,V&gt; head;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * The tail (youngest) of the doubly linked list.</span></span><br><span class="line"><span class="comment"> * 尾部，最后被插入的节点</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">transient</span> LinkedHashMap.Entry&lt;K,V&gt; tail;</span><br></pre></td></tr></table></figure>

<p><img src="https://masuo-github-image.oss-cn-beijing.aliyuncs.com/image/20210722193012.png" alt="image-20210722192940676"></p>
<p>再来看Linked Hash Map的构造函数，一共五个构造函数，同Hash Map，有带参和不带参的。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Constructs an empty insertion-ordered &lt;tt&gt;LinkedHashMap&lt;/tt&gt; instance</span></span><br><span class="line"><span class="comment"> * with the specified initial capacity and load factor.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span>  initialCapacity the initial capacity</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span>  loadFactor      the load factor</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@throws</span> IllegalArgumentException if the initial capacity is negative</span></span><br><span class="line"><span class="comment"> *         or the load factor is nonpositive</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">LinkedHashMap</span><span class="params">(<span class="keyword">int</span> initialCapacity, <span class="keyword">float</span> loadFactor)</span> </span>&#123;</span><br><span class="line">    <span class="comment">//这里指向HashMap的双参构造函数</span></span><br><span class="line">    <span class="keyword">super</span>(initialCapacity, loadFactor);</span><br><span class="line">    <span class="comment">//决定了顺序，默认为false，此时维护的是插入的顺序</span></span><br><span class="line">    accessOrder = <span class="keyword">false</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Constructs an empty insertion-ordered &lt;tt&gt;LinkedHashMap&lt;/tt&gt; instance</span></span><br><span class="line"><span class="comment"> * with the specified initial capacity and a default load factor (0.75).</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span>  initialCapacity the initial capacity</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@throws</span> IllegalArgumentException if the initial capacity is negative</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">LinkedHashMap</span><span class="params">(<span class="keyword">int</span> initialCapacity)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">super</span>(initialCapacity);</span><br><span class="line">    accessOrder = <span class="keyword">false</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Constructs an empty insertion-ordered &lt;tt&gt;LinkedHashMap&lt;/tt&gt; instance</span></span><br><span class="line"><span class="comment"> * with the default initial capacity (16) and load factor (0.75).</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">LinkedHashMap</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">super</span>();</span><br><span class="line">    accessOrder = <span class="keyword">false</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Constructs an insertion-ordered &lt;tt&gt;LinkedHashMap&lt;/tt&gt; instance with</span></span><br><span class="line"><span class="comment"> * the same mappings as the specified map.  The &lt;tt&gt;LinkedHashMap&lt;/tt&gt;</span></span><br><span class="line"><span class="comment"> * instance is created with a default load factor (0.75) and an initial</span></span><br><span class="line"><span class="comment"> * capacity sufficient to hold the mappings in the specified map.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span>  m the map whose mappings are to be placed in this map</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@throws</span> NullPointerException if the specified map is null</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">LinkedHashMap</span><span class="params">(Map&lt;? extends K, ? extends V&gt; m)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">super</span>();</span><br><span class="line">    accessOrder = <span class="keyword">false</span>;</span><br><span class="line">    putMapEntries(m, <span class="keyword">false</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Constructs an empty &lt;tt&gt;LinkedHashMap&lt;/tt&gt; instance with the</span></span><br><span class="line"><span class="comment"> * specified initial capacity, load factor and ordering mode.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span>  initialCapacity the initial capacity</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span>  loadFactor      the load factor</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span>  accessOrder     the ordering mode - &lt;tt&gt;true&lt;/tt&gt; for</span></span><br><span class="line"><span class="comment"> *         access-order, &lt;tt&gt;false&lt;/tt&gt; for insertion-order</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@throws</span> IllegalArgumentException if the initial capacity is negative</span></span><br><span class="line"><span class="comment"> *         or the load factor is nonpositive</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">LinkedHashMap</span><span class="params">(<span class="keyword">int</span> initialCapacity,</span></span></span><br><span class="line"><span class="params"><span class="function">                     <span class="keyword">float</span> loadFactor,</span></span></span><br><span class="line"><span class="params"><span class="function">                     <span class="keyword">boolean</span> accessOrder)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">super</span>(initialCapacity, loadFactor);</span><br><span class="line">    <span class="keyword">this</span>.accessOrder = accessOrder;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>通过以上代码，可以发现他除了按照HashMap的结构存储数据之外，还通过双向链表将数据连接起来，如图所示（这是头插法，即java1.7之前）</p>
<p><img src="https://masuo-github-image.oss-cn-beijing.aliyuncs.com/image/20210726113913.png" alt="img"></p>
<p>引自：<a target="_blank" rel="noopener" href="https://blog.csdn.net/u012860938/article/details/95613684">https://blog.csdn.net/u012860938/article/details/95613684</a> 。</p>
<h4 id="Tree-Map"><a href="#Tree-Map" class="headerlink" title="Tree Map"></a>Tree Map</h4><p>先看类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">TreeMap</span>&lt;<span class="title">K</span>,<span class="title">V</span>&gt;</span></span><br><span class="line"><span class="class">    <span class="keyword">extends</span> <span class="title">AbstractMap</span>&lt;<span class="title">K</span>,<span class="title">V</span>&gt;//继承自<span class="title">AbstractMap</span>,大多都是继承自这个</span></span><br><span class="line"><span class="class">    <span class="keyword">implements</span> <span class="title">NavigableMap</span>&lt;<span class="title">K</span>,<span class="title">V</span>&gt;, <span class="title">Cloneable</span>, <span class="title">java</span>.<span class="title">io</span>.<span class="title">Serializable</span></span></span><br><span class="line"><span class="class">    //实现了以上三个接口，分别是？，可<span class="title">clone</span>，可序列化第一个第一次见</span></span><br><span class="line"><span class="class">    </span></span><br><span class="line"><span class="class"><span class="title">public</span> <span class="title">interface</span> <span class="title">NavigableMap</span>&lt;<span class="title">K</span>,<span class="title">V</span>&gt; <span class="keyword">extends</span> <span class="title">SortedMap</span>&lt;<span class="title">K</span>,<span class="title">V</span>&gt; </span></span><br><span class="line"><span class="class">    //往下查看看到这个接口继承自<span class="title">SortedMap</span>，这就使得<span class="title">TreeMap</span>间接继承了<span class="title">SortedMap</span>，使得它有序性得以保障</span></span><br></pre></td></tr></table></figure>



<p>再来看一下常量</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//比较器</span></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">final</span> Comparator&lt;? <span class="keyword">super</span> K&gt; comparator;</span><br><span class="line"></span><br><span class="line"><span class="comment">//节点，k-v对</span></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">transient</span> Entry&lt;K,V&gt; root;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * The number of entries in the tree</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">transient</span> <span class="keyword">int</span> size = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * The number of structural modifications to the tree.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">transient</span> <span class="keyword">int</span> modCount = <span class="number">0</span>;</span><br></pre></td></tr></table></figure>

<p>构造函数</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">TreeMap</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    comparator = <span class="keyword">null</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Constructs a new, empty tree map, ordered according to the given</span></span><br><span class="line"><span class="comment"> * comparator.  </span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">TreeMap</span><span class="params">(Comparator&lt;? <span class="keyword">super</span> K&gt; comparator)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">this</span>.comparator = comparator;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Constructs a new tree map containing the same mappings as the given</span></span><br><span class="line"><span class="comment"> * map, ordered according to the &lt;em&gt;natural ordering&lt;/em&gt; of its keys.</span></span><br><span class="line"><span class="comment"> * All keys inserted into the new map must implement the &#123;<span class="doctag">@link</span></span></span><br><span class="line"><span class="comment"> * Comparable&#125; interface.  </span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">TreeMap</span><span class="params">(Map&lt;? extends K, ? extends V&gt; m)</span> </span>&#123;</span><br><span class="line">    comparator = <span class="keyword">null</span>;</span><br><span class="line">    putAll(m);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Constructs a new tree map containing the same mappings and</span></span><br><span class="line"><span class="comment"> * using the same ordering as the specified sorted map.  This</span></span><br><span class="line"><span class="comment"> * method runs in linear time.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">TreeMap</span><span class="params">(SortedMap&lt;K, ? extends V&gt; m)</span> </span>&#123;</span><br><span class="line">    comparator = m.comparator();</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        buildFromSorted(m.size(), m.entrySet().iterator(), <span class="keyword">null</span>, <span class="keyword">null</span>);</span><br><span class="line">    &#125; <span class="keyword">catch</span> (java.io.IOException cannotHappen) &#123;</span><br><span class="line">    &#125; <span class="keyword">catch</span> (ClassNotFoundException cannotHappen) &#123;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>基于红黑树实现的Tree Map自带排序，但是了解不多，暂不多说。下次一定。</p>
<h4 id="Concurrent-Hash-Map"><a href="#Concurrent-Hash-Map" class="headerlink" title="Concurrent Hash Map"></a>Concurrent Hash Map</h4><p><img src="https://masuo-github-image.oss-cn-beijing.aliyuncs.com/image/20210726154140.png" alt="image-20210726154104842"></p>
<p>以上就是Concurrent Hash Map的结构。</p>
<p>在Concurrent HashMap的文档开头提到，</p>
<p>存储结构：</p>
<p><img src="https://masuo-github-image.oss-cn-beijing.aliyuncs.com/image/20210726154521.png" alt="image-20210726154519429"></p>
<p>实现与HashMap类似，唯一的不同是他采用了分段锁（Segment）实现，每个分段锁维护着几个桶（Hash Entry），多个线程可以访问不同分段锁上的桶，提高并发性，并发度就是Segment的数量。</p>
<hr>
<h2 id="反射"><a href="#反射" class="headerlink" title="反射"></a>反射</h2><p>首先，什么是反射？说出来你可能不太相信，他强大到可以取到类的私有变量。Java的反射机制是在运行状态中，对于任意的一个类都能知道这个类的所有属性和方法，对于任意一个对象，都能够调用他的任意一个方法和属性，这种动态的获取信息以及动态的调用对象方法的功能称为Java语言的反射机制。</p>
<p>简单来说，反射就是把Java类中的各种成分映射成一个个Java对象。</p>
<p>等学完类的加载机制再回来看这一块把。</p>
<p>(更新于2021-9-2)</p>
<blockquote>
<p>Java的<strong>反射</strong>机制就是在运行状态中,对于任意一个类,都可以获取它的所有的属性和方法,对于任意一个对象,都能够任意调用它的一个方法和属性.</p>
</blockquote>
<p><strong>类加载：</strong></p>
<p>每个类都有一个<strong>class对象</strong>，包含了与类有关的信息。当编译一个新类时，会产生一个同名的.class文件，该文件内容保存着class对象。</p>
<p>类加载相当于class对象的加载，类在第一次使用时才动态加载到JVM中（这种在需要的时候才加载被称为<strong>懒加载机制</strong>，相对的，一开始就被加载的机制被称为<strong>饿汉式加载机制</strong>），也可以使用Class.forName(“com.mysql.jdbc.driver”)这种方式来控制类的加载，该方法会返回一个class对象。</p>
<p>反射可以提供运行时类的信息，并且这个类可以在<strong>运行时</strong>才加载进来，甚至在<strong>编译时期</strong>该类的.class不存在也可以加载进来。</p>
<p>参照：<a target="_blank" rel="noopener" href="https://www.sczyh30.com/posts/Java/java-reflection-1/">https://www.sczyh30.com/posts/Java/java-reflection-1/</a></p>
<hr>
<h2 id="异常"><a href="#异常" class="headerlink" title="异常"></a>异常</h2><p>你以为Exception是所有异常类的父类？不不不，我上次使用的时候发现Throwable才是（不算object类）。</p>
<p>因为异常还包括Error，所以Throwable包括Error和Exception，其中error用来处理JVM无法解决的错误。</p>
<p>Exception又分为两种异常：</p>
<ul>
<li>受检异常：使用try…catch…语句可以捕获异常并使程序继续运行（即使程序从异常中恢复，不会中断程序）。</li>
<li>非受检异常：是程序运行时出错，此时程序崩溃且无法回复（程序抛出异常并中断）。例如除数为0会引发Arithmetic Exception，此时程序会直接退出。</li>
</ul>
<p><img src="https://masuo-github-image.oss-cn-beijing.aliyuncs.com/image/20210717210858.png" alt="image-20210717210832169"></p>
<h3 id="ERROR"><a href="#ERROR" class="headerlink" title="ERROR"></a>ERROR</h3><blockquote>
<p>程序遇到错误，不能继续运行或恢复。程序不能自己处理的叫错误。</p>
</blockquote>
<h3 id="EXCEPTION"><a href="#EXCEPTION" class="headerlink" title="EXCEPTION"></a>EXCEPTION</h3><blockquote>
<p>系统遇到异常，可以被捕获或抛出。可以通过改变程序逻辑来使程序正常运行。</p>
<p>异常又分受检异常和运行时异常。</p>
</blockquote>
<h4 id="受检异常"><a href="#受检异常" class="headerlink" title="受检异常"></a>受检异常</h4><blockquote>
<p><code>checked Exception</code>，在程序编译器就对异常进行检查</p>
</blockquote>
<h4 id="运行时异常"><a href="#运行时异常" class="headerlink" title="运行时异常"></a>运行时异常</h4><blockquote>
<p>在程序运行期间对异常进行处理。</p>
</blockquote>
<h2 id="泛型"><a href="#泛型" class="headerlink" title="泛型"></a>泛型</h2><p>啊，泛型啊，蛮常见的还算，例如ArrayList，通常使用T来声明。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> masuo</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@create</span> 2021/7/17 21:36</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Description</span> 泛型</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Genericity</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        genericity();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">genericity</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="class"><span class="keyword">class</span> <span class="title">Box</span>&lt;<span class="title">T</span>&gt;</span>&#123;</span><br><span class="line">            <span class="keyword">private</span> T t;</span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="title">Box</span><span class="params">(T t)</span></span>&#123;</span><br><span class="line">                <span class="keyword">this</span>.t = t;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">public</span> Class&lt;?&gt; getClassName()&#123;</span><br><span class="line">                <span class="keyword">return</span> t.getClass();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        Box&lt;String&gt; b1 = <span class="keyword">new</span> Box&lt;&gt;(<span class="string">&quot;ss&quot;</span>);</span><br><span class="line">        Box&lt;Integer&gt; b2 = <span class="keyword">new</span> Box&lt;&gt;(<span class="number">111</span>);</span><br><span class="line">        System.out.println(b1.getClassName());</span><br><span class="line">        System.out.println(b2.getClassName());</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h1 id="Java核心技术"><a href="#Java核心技术" class="headerlink" title="Java核心技术"></a>Java核心技术</h1><p>开新篇了，上一篇还存在很多漏洞，但是看容器两个星期之后，现在脑子已经是一团浆糊了（大概率是劳逸不结合的原因吧），觉得是时候给脑子换个环境了。正好，目前只剩下两大最难啃的核心了，来慢慢消化吧。</p>
<h2 id="多线程"><a href="#多线程" class="headerlink" title="多线程"></a>多线程</h2><h4 id="准备"><a href="#准备" class="headerlink" title="准备"></a>准备</h4><ul>
<li><p>进程</p>
</li>
<li><p>并行、并发</p>
</li>
<li></li>
</ul>
<h3 id="七大核心参数"><a href="#七大核心参数" class="headerlink" title="七大核心参数"></a>七大核心参数</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">ThreadPoolExecutor</span><span class="params">(<span class="keyword">int</span> corePoolSize,//核心线程数</span></span></span><br><span class="line"><span class="params"><span class="function">                          <span class="keyword">int</span> maximumPoolSize,//允许在线程池中的最大线程数量</span></span></span><br><span class="line"><span class="params"><span class="function">                          <span class="keyword">long</span> keepAliveTime,//空闲线程允许的存活时间</span></span></span><br><span class="line"><span class="params"><span class="function">                          TimeUnit unit,//时间单位</span></span></span><br><span class="line"><span class="params"><span class="function">                          BlockingQueue&lt;Runnable&gt; workQueue,//工作队列</span></span></span><br><span class="line"><span class="params"><span class="function">                          ThreadFactory threadFactory,//线程工厂</span></span></span><br><span class="line"><span class="params"><span class="function">                          RejectedExecutionHandler handler)</span> </span>&#123;<span class="comment">//拒绝策略</span></span><br><span class="line">    <span class="keyword">if</span> (corePoolSize &lt; <span class="number">0</span> ||</span><br><span class="line">        maximumPoolSize &lt;= <span class="number">0</span> ||</span><br><span class="line">        maximumPoolSize &lt; corePoolSize ||</span><br><span class="line">        keepAliveTime &lt; <span class="number">0</span>)</span><br><span class="line">        <span class="comment">//异常</span></span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException();</span><br><span class="line">    <span class="keyword">if</span> (workQueue == <span class="keyword">null</span> || threadFactory == <span class="keyword">null</span> || handler == <span class="keyword">null</span>)</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> NullPointerException();</span><br><span class="line">    <span class="keyword">this</span>.acc = System.getSecurityManager() == <span class="keyword">null</span> ?</span><br><span class="line">        <span class="keyword">null</span> :</span><br><span class="line">    AccessController.getContext();</span><br><span class="line">    <span class="keyword">this</span>.corePoolSize = corePoolSize;</span><br><span class="line">    <span class="keyword">this</span>.maximumPoolSize = maximumPoolSize;</span><br><span class="line">    <span class="keyword">this</span>.workQueue = workQueue;</span><br><span class="line">    <span class="keyword">this</span>.keepAliveTime = unit.toNanos(keepAliveTime);</span><br><span class="line">    <span class="keyword">this</span>.threadFactory = threadFactory;</span><br><span class="line">    <span class="keyword">this</span>.handler = handler;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h4 id="corePoolSize"><a href="#corePoolSize" class="headerlink" title="corePoolSize"></a>corePoolSize</h4><blockquote>
<p>线程池核心线程数量</p>
<p>线程池会维护一个最小的线程数量，即使这些线程处于空闲状态，他们也不会被销毁。</p>
<p>除非设置了 <code>allowCoreThreadTimeOut</code> ，这里的最小线程数量就是 <code>corePoolSize</code></p>
</blockquote>
<figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure>



<h4 id="maximumPoolSize"><a href="#maximumPoolSize" class="headerlink" title="maximumPoolSize"></a>maximumPoolSize</h4><blockquote>
<p>线程池最大线程数量</p>
<p>一个任务再提交后会查看是否有空闲存活线程，如果有，则将任务交给空闲线程执行。</p>
<p>如果没有，则缓存到工作队列，如果工作队列满了，就会新建一个线程，然后从头部取出一个任务交给新线程处理，将刚提交的任务放在队尾。</p>
</blockquote>
<figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="code">```</span></span><br><span class="line"><span class="code"></span></span><br><span class="line"><span class="code"></span></span><br><span class="line"><span class="code"></span></span><br><span class="line"><span class="code">#### keepAliveTime</span></span><br><span class="line"><span class="code"></span></span><br><span class="line"><span class="code">&gt; 空闲线程存活时间</span></span><br><span class="line"><span class="code"></span></span><br><span class="line"><span class="code">```</span>markdown</span><br></pre></td></tr></table></figure>



<h4 id="TimeUnit"><a href="#TimeUnit" class="headerlink" title="TimeUnit"></a>TimeUnit</h4><blockquote>
<p>时间单位，空闲线程存活时间的时间单位。</p>
</blockquote>
<figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="code">```</span></span><br><span class="line"><span class="code"></span></span><br><span class="line"><span class="code"></span></span><br><span class="line"><span class="code"></span></span><br><span class="line"><span class="code">#### workQueue</span></span><br><span class="line"><span class="code"></span></span><br><span class="line"><span class="code">&gt; 工作队列</span></span><br><span class="line"><span class="code">&gt;</span></span><br><span class="line"><span class="code">&gt; 有以下四种</span></span><br><span class="line"><span class="code">&gt;</span></span><br><span class="line"><span class="code">&gt; - `ArrayBlockingQueue`</span></span><br><span class="line"><span class="code">&gt;</span></span><br><span class="line"><span class="code">&gt;     基于数组的有界阻塞队列，按FIFO排序。新任务进来后，会放到该队列的队尾，有界的数组可以防止资源耗尽问题。</span></span><br><span class="line"><span class="code">&gt;     当线程池中线程数量达到corePoolSize后，再有新任务进来，则会将任务放入该队列的队尾，等待被调度。</span></span><br><span class="line"><span class="code">&gt;     如果队列已经是满的，则创建一个新线程，如果线程数量已经达到maxPoolSize，则会执行拒绝策略。</span></span><br><span class="line"><span class="code">&gt;</span></span><br><span class="line"><span class="code">&gt; - `LinkedBlockingQuene`</span></span><br><span class="line"><span class="code">&gt;     基于链表的无界阻塞队列（其实最大容量为Interger.MAX），按照FIFO排序。由于该队列的近似无界性，</span></span><br><span class="line"><span class="code">&gt;     当线程池中线程数量达到corePoolSize后，再有新任务进来，会一直存入该队列，而不会去创建新线程直到maxPoolSize，</span></span><br><span class="line"><span class="code">&gt;     因此使用该工作队列时，参数maxPoolSize其实是不起作用的。</span></span><br><span class="line"><span class="code">&gt;</span></span><br><span class="line"><span class="code">&gt; - `SynchronousQuene`</span></span><br><span class="line"><span class="code">&gt;     一个不缓存任务的阻塞队列，生产者放入一个任务必须等到消费者取出这个任务。也就是说新任务进来时，不会缓存，</span></span><br><span class="line"><span class="code">&gt;     而是直接被调度执行该任务，如果没有可用线程，则创建新线程，如果线程数量达到maxPoolSize，则执行拒绝策略。</span></span><br><span class="line"><span class="code">&gt;</span></span><br><span class="line"><span class="code">&gt; - `PriorityBlockingQueue`</span></span><br><span class="line"><span class="code">&gt;     具有优先级的无界阻塞队列，优先级通过参数Comparator实现。</span></span><br><span class="line"><span class="code"></span></span><br><span class="line"><span class="code">```</span>markdown</span><br></pre></td></tr></table></figure>



<h4 id="threadFactory"><a href="#threadFactory" class="headerlink" title="threadFactory"></a>threadFactory</h4><blockquote>
<p>线程工厂，可以用来设定线程名、是否为daemon线程</p>
</blockquote>
<figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line"><span class="code">```</span></span><br><span class="line"><span class="code"></span></span><br><span class="line"><span class="code"></span></span><br><span class="line"><span class="code"></span></span><br><span class="line"><span class="code">#### handler</span></span><br><span class="line"><span class="code"></span></span><br><span class="line"><span class="code">&gt; 拒绝策略</span></span><br><span class="line"><span class="code"></span></span><br><span class="line"><span class="code">##### CallerRunsPolicy</span></span><br><span class="line"><span class="code"></span></span><br><span class="line"><span class="code">该策略下，在调用者线程中直接执行被拒绝任务的run(方法。如果线程池已经shutdown，则直接抛弃该任务。</span></span><br><span class="line"><span class="code"></span></span><br><span class="line"><span class="code">##### AbortPolicy</span></span><br><span class="line"><span class="code"></span></span><br><span class="line"><span class="code">中止策略，该模式下，直接抛弃任务，并抛出异常。</span></span><br><span class="line"><span class="code"></span></span><br><span class="line"><span class="code">##### DiscardPolicy</span></span><br><span class="line"><span class="code"></span></span><br><span class="line"><span class="code">丢弃策略，该模式下，直接丢弃任务。</span></span><br><span class="line"><span class="code"></span></span><br><span class="line"><span class="code">##### DiscardOldestPolicy</span></span><br><span class="line"><span class="code"></span></span><br><span class="line"><span class="code">丢弃最老策略，该模式下，丢弃最先进入队列的任务，然后尝试将此次任务加入队列的队尾。</span></span><br><span class="line"><span class="code"></span></span><br><span class="line"><span class="code"></span></span><br><span class="line"><span class="code"></span></span><br><span class="line"><span class="code"></span></span><br><span class="line"><span class="code"></span></span><br><span class="line"><span class="code">---</span></span><br><span class="line"><span class="code"></span></span><br><span class="line"><span class="code">## I/O</span></span><br><span class="line"><span class="code"></span></span><br><span class="line"><span class="code">```</span>mbox</span><br><span class="line">IO即输入输出（Input/Output）。</span><br><span class="line"></span><br><span class="line">计算机结构层面：</span><br><span class="line"><span class="bullet"> *</span> 冯诺依曼结构中指出，计算机由：运算器、控制器、存储器、输入设备、输出设备组成。</span><br><span class="line"><span class="bullet"> *</span> 这里的输入输出描述了计算机系统与外界之间的通讯过程。</span><br><span class="line"><span class="bullet"> *</span> 输入设备（比如键盘）和输出设备（比如显示屏）都属于外部设备。网卡、硬盘这种既可以属于输入设备，也可以属于输出设备。</span><br><span class="line"></span><br><span class="line">应用程序层面：</span><br><span class="line"><span class="bullet"> *</span> 为了保证操作系统的稳定性和安全性，进程的地址空间被划分为用户空间（User space）和内核空间（Kernel space）</span><br><span class="line"><span class="bullet"> *</span> 我们平时的应用程序都是运行在用户空间的，只有内核空间才能进行系统态级别的资源有关的操作，如文件管理，进程通信，内存管理等。</span><br><span class="line"><span class="bullet"> *</span> 并且，用户空间不能直接访问内核空间。当我们想要执行IO操作时，由于本身没有操作权限，我们需要向系统发起请求（详情看下面解释）。</span><br><span class="line"><span class="bullet"> *</span> 当应用程序发起IO调用请求之后，会经历两个步骤</span><br><span class="line"> 	1）内核等待IO设备准备好数据</span><br><span class="line"> 	2）内核将数据从内核空间拷贝到用户空间</span><br></pre></td></tr></table></figure>

<p><img src="https://masuo-github-image.oss-cn-beijing.aliyuncs.com/image/20211221170028.webp" alt="冯诺依曼体系结构"></p>
<blockquote>
<p>最常见的IO就是<strong>磁盘IO</strong>（读写文件）和<strong>网络IO</strong>（网络请求和响应）。</p>
</blockquote>
<h3 id="准备-1"><a href="#准备-1" class="headerlink" title="准备"></a>准备</h3><p>如果你的目的很单纯只是想知道如何操作文件的读写那么可以直接往下找自己想要的了。</p>
<p>or</p>
<p>了解以下知识，如果你已了解可跳过。</p>
<ul>
<li><strong>同步</strong>、<strong>异步</strong>：同步和异步关注的是<strong>消息发送机制(send)</strong>    </li>
<li><strong>阻塞</strong>、<strong>非阻塞</strong>：阻塞和非阻塞关注的是<strong>消息接收机制(receive)</strong></li>
</ul>
<h4 id="详释"><a href="#详释" class="headerlink" title="详释"></a><em>详释</em></h4><blockquote>
<p>进程间的通信是通过send()和receive()两种基本操作实现的。具体如何实现，存在不同的设计。消息的传递可能是阻塞的或非阻塞的—也被熟知为同步或异步的。</p>
</blockquote>
<p>从上面的信息可知，阻塞非阻塞和同步异步可以说是一样的。那么他们的不同是啥呢？往下看下面的解释。</p>
<ul>
<li>**阻塞式发送(Blocking send)**：发送方进程会一直被阻塞直到消息被接收方进程或邮箱收到。</li>
<li>**非阻塞式发送(Nonblocking send)**：发送方进程调用send后，就可以直接执行下面的代码。</li>
<li>**阻塞式接收(Blocking receive)**：接收方调用receive后一直被阻塞，直到消息到达。</li>
<li>**非阻塞式接收(Nonblocking receive)**：接收方调用receive后，要么得到结果，要么得到空值。</li>
</ul>
<p>==以上消息的发送和接收方式可以自由组合。==</p>
<p>**同步(synchronous)**：同步即等待，类似于串联，同步指调用方在调用某个东西之后需等待被调用方完成才能进行下一步操作。</p>
<p>**异步(asynchronous)**：异步即不等待，异步指调用方在执行完调用命令之后就进行下一步操作了，无需等待被调用方完成，只是在被调用方完成该命令之后返回消息。</p>
<p><strong>阻塞（block）</strong>：阻塞是指在调用结果返回之前，线程是会被挂起的，当接收到返回消息时，才会继续执行</p>
<p><strong>非阻塞（non-block）</strong>：与阻塞相反，当函数调用不能立刻得到结果的时候，该函数会立刻返回，执行下面的代码，不会阻塞当前线程。</p>
<h4 id="异同"><a href="#异同" class="headerlink" title="异同"></a>异同</h4><blockquote>
<p>上面的同步异步与阻塞非阻塞看似原理非常相似，那他们有什么不同点呢？如何区分？</p>
</blockquote>
<ul>
<li>同步异步指的是<strong>消息发送</strong>的机制，</li>
</ul>
<blockquote>
<p>例如使用浏览器访问一个网站，需要多次请求服务端，才能加载完整个页面的内容。</p>
<p><strong>同步</strong>的操作如下：浏览器首先发送第一个请求，等待服务器回复后，再发送第二个请求，依次类推，直到所有请求完成。</p>
<p><strong>异步</strong>的操作如下：浏览器发送第一个请求，可以不用等待服务器返回，可以继续发送第二个请求。</p>
</blockquote>
<ul>
<li>阻塞非阻塞指的是<strong>消息接受</strong>的机制</li>
</ul>
<blockquote>
<p>例如进行需要read数据，</p>
<p>阻塞方式操作流程是：如果没有数据，则read会一直等着数据到来，才能进行后续的动作</p>
<p>非阻塞则是read没有到数据后，则可以进行后续的动作，当有数据的时候再回来读取。</p>
</blockquote>
<p>参考：<a target="_blank" rel="noopener" href="https://blog.csdn.net/qq_35503998/article/details/82835517">https://blog.csdn.net/qq_35503998/article/details/82835517</a></p>
<blockquote>
<p><strong>IO的本质是流的传输，并且流是单向的。</strong></p>
</blockquote>
<h3 id="分类"><a href="#分类" class="headerlink" title="分类"></a>分类</h3><h4 id="流的流向"><a href="#流的流向" class="headerlink" title="流的流向"></a>流的流向</h4><ul>
<li>输入流</li>
<li>输出流</li>
</ul>
<h4 id="操作单元"><a href="#操作单元" class="headerlink" title="操作单元"></a>操作单元</h4><ul>
<li>字节流</li>
<li>字符流</li>
</ul>
<h4 id="Java中常见IO分类"><a href="#Java中常见IO分类" class="headerlink" title="Java中常见IO分类"></a>Java中常见IO分类</h4><ul>
<li>BIO：同步阻塞型IO,Blocking IO</li>
<li>NIO：同步非阻塞IO,Non-Blocking IO</li>
<li>AIO：异步非阻塞IO,Asynchronous IO</li>
</ul>
<h3 id="IO"><a href="#IO" class="headerlink" title="IO"></a>IO</h3><blockquote>
<p>Java IO流涉及很多个类，这些类都是由以下四个抽象类派生出来的.</p>
<p>Input Stream/Reader：输入流基类，字节/字符</p>
<p>Output Stream/Writer：输出流基类，字节/字符</p>
</blockquote>
<blockquote>
<p>在这里，你可能理解Input是输入流，Output是输出流，但是你可能在疑惑Reader为什么是输入流，Writer为什么是输出流。（以下是个人理解）</p>
<p>因为这里Reader是从<strong>磁盘</strong>或<strong>网络</strong>上将文件读到<strong>内存</strong>，对于<strong>内存</strong>来说，这是一个输入流。</p>
<p>相对的，Writer是将文件内容从<strong>内存</strong>写入到<strong>磁盘</strong>或<strong>网络</strong>上，对于<strong>内存</strong>来说，这是一个输出流。</p>
<p>内存也称运存，运行内存。</p>
<p>为什么是相对<strong>内存</strong>呢？因为我们的程序是运行在<strong>内存</strong>上的，内存越大，能运行的应用程序越多。</p>
</blockquote>
<p><img src="https://masuo-github-image.oss-cn-beijing.aliyuncs.com/image/20211222102906.png" alt="image-20211222102901483"></p>
<h4 id="IO分类图"><a href="#IO分类图" class="headerlink" title="IO分类图"></a>IO分类图</h4><p><img src="https://masuo-github-image.oss-cn-beijing.aliyuncs.com/image/20211221174013.png" alt="Java I_O"></p>
<p><img src="https://masuo-github-image.oss-cn-beijing.aliyuncs.com/image/Java%20IO.png" alt="Java IO"></p>
<p>既然IO分为字节流和字符流，那么字节流与字符流有什么不一样呢？</p>
<p>如果你不知道的话，相信你肯定也会有这个疑问。</p>
<p>我们知道<strong>字符</strong>与<strong>字节</strong>的区别，</p>
<p><strong>字符</strong>：一个字符根据编码的不同，对应的字节也不同，如 UTF-8 编码是 3 个字节，中文编码是 2 个字节</p>
<p><strong>字节</strong>：字节是计算存储容量的基础单位</p>
<blockquote>
<p>文件的本质是数据，数据的单位是字节，我们在存储数据的方式决定了我们读取数据的方式。</p>
<p>字节流用来处理二进制文件（图片、MP3、视频文件），</p>
<p>字符流用来处理文本文件（可以看做是特殊的二进制文件，使用了某种编码，人可以阅读）。</p>
<p>字节是给计算机看的，字符才是给人看的。</p>
</blockquote>
<p>举个:chestnut:</p>
<blockquote>
<p>这里有个小坑，在实验时你会发现的。</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> JavaCore.MyIO.IO;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.junit.Test;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> javax.annotation.processing.FilerException;</span><br><span class="line"><span class="keyword">import</span> java.io.*;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> masuo</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@date</span>: 2021/12/20/ 下午9:07</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@description</span> IO流--FileIO</span></span><br><span class="line"><span class="comment"> * 按照流的流向可划分为 【输入流】 和 【输出流】</span></span><br><span class="line"><span class="comment"> * 按照操作单元可划分为 【字节流】 和 【字符流】</span></span><br><span class="line"><span class="comment"> * IO即输入输出（Input/Output）。</span></span><br><span class="line"><span class="comment"> * 冯诺依曼结构中指出，计算机由：运算器、控制器、存储器、输入设备、输出设备组成。</span></span><br><span class="line"><span class="comment"> * 这里的输入输出描述了计算机系统与外界之间的通讯过程。</span></span><br><span class="line"><span class="comment"> * &lt;p&gt;</span></span><br><span class="line"><span class="comment"> * 在应用程序层面：</span></span><br><span class="line"><span class="comment"> * 为了保证操作系统的稳定性和安全性，进程的地址空间被划分为用户空间（User space）和内核空间（Kernel space）</span></span><br><span class="line"><span class="comment"> * 我们平时的应用程序都是运行在用户空间的，只有内核空间才能进行系统态级别的资源有关的操作，如文件管理，进程通信，内存管理等。</span></span><br><span class="line"><span class="comment"> * 并且，用户空间不能直接访问内核空间。当我们想要执行IO操作时，由于本身没有操作权限，我们需要向系统发起请求。</span></span><br><span class="line"><span class="comment"> * &lt;p&gt;</span></span><br><span class="line"><span class="comment"> * 最常见的IO就是磁盘IO（读写文件）和网络IO（网络请求和响应）。</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">FileIO</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//Java IO流涉及很多个类，这些类都是由以下四个抽象类派生出来的.</span></span><br><span class="line">    <span class="comment">// InputStream/Reader：输入流基类，字节/字符</span></span><br><span class="line">    <span class="comment">// OutputStream/Writer：输出流基类，字节/字符</span></span><br><span class="line"></span><br><span class="line">    <span class="meta">@Test</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">FIleI</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        String fileName = <span class="string">&quot;../JavaCode/src/files/outputStream.txt&quot;</span>;</span><br><span class="line">        File file = <span class="keyword">new</span> File(fileName);</span><br><span class="line">        <span class="comment">// 输入流类的使用</span></span><br><span class="line"></span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="keyword">if</span> (!file.exists()) &#123;</span><br><span class="line">                <span class="keyword">if</span>(!file.createNewFile())&#123;</span><br><span class="line">                    <span class="keyword">throw</span> <span class="keyword">new</span> FilerException(<span class="string">&quot;文件创建失败！&quot;</span>);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="comment">//1、InputStream -- FileInputStream</span></span><br><span class="line">            &#123;</span><br><span class="line">                InputStream is;</span><br><span class="line"></span><br><span class="line">                <span class="comment">//如果我们想要读取完整的文件，就需要循环读取</span></span><br><span class="line">                <span class="comment">//方法一：循环读取字节</span></span><br><span class="line">                &#123;</span><br><span class="line">                    is = <span class="keyword">new</span> FileInputStream(file);</span><br><span class="line">                    System.out.println(<span class="string">&quot;每次读取一个字节：&quot;</span> + is.read());<span class="comment">//会输出读取到的第一个字节</span></span><br><span class="line">                    <span class="keyword">int</span> date;</span><br><span class="line">                    <span class="keyword">while</span> ((date = is.read()) != -<span class="number">1</span>) &#123;</span><br><span class="line">                        <span class="comment">//读取到的数据不是-1时，则证明可以继续读取</span></span><br><span class="line">                        System.out.print(date);<span class="comment">//读取一个字节，返回字节的int值</span></span><br><span class="line">                        System.out.print(<span class="string">&#x27; &#x27;</span>);</span><br><span class="line">                        System.out.print((<span class="keyword">char</span>) (date));<span class="comment">//将字节转换成字符</span></span><br><span class="line">                        System.out.print(<span class="string">&#x27; &#x27;</span>);</span><br><span class="line">                        System.out.print((<span class="keyword">byte</span>) (date));<span class="comment">//将字节转换成字节</span></span><br><span class="line">                        System.out.println();</span><br><span class="line">                    &#125;</span><br><span class="line">                    is.close();</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="comment">//方法二：利用缓冲一次性读取大量数据读取，将读取到的数据缓冲到数组中</span></span><br><span class="line">                &#123;</span><br><span class="line">                    is = <span class="keyword">new</span> FileInputStream(file);</span><br><span class="line">                    <span class="comment">// 这种缓冲读取，也是Buffer的实现原理</span></span><br><span class="line">                    <span class="keyword">byte</span>[] bytes = <span class="keyword">new</span> <span class="keyword">byte</span>[<span class="number">17</span>];</span><br><span class="line">                    <span class="comment">//这里返回的int值是读取到的最后一位的下标</span></span><br><span class="line">                    <span class="keyword">int</span> inputStreamIndex = is.read(bytes);</span><br><span class="line">                    System.out.println(<span class="string">&quot;read(byte[])返回的是下标，下标为:&quot;</span> + inputStreamIndex);</span><br><span class="line">                    <span class="keyword">for</span> (<span class="keyword">byte</span> aByte : bytes) &#123;</span><br><span class="line">                        System.out.print(aByte + <span class="string">&quot; &quot;</span>);</span><br><span class="line">                    &#125;</span><br><span class="line">                    System.out.println(<span class="string">&quot;读取结束！&quot;</span>);</span><br><span class="line">                    <span class="comment">//此时再读取将读到 -1</span></span><br><span class="line">                    System.out.println(<span class="string">&quot;在读取则为：&quot;</span> + is.read());</span><br><span class="line">                    is.close();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="comment">//2、Reader -- FileReader</span></span><br><span class="line">            &#123;</span><br><span class="line">                Reader reader;</span><br><span class="line"></span><br><span class="line">                <span class="comment">//方法一：循环读取</span></span><br><span class="line">                &#123;</span><br><span class="line">                    reader = <span class="keyword">new</span> FileReader(file);</span><br><span class="line">                    <span class="comment">//每次读取一个字符</span></span><br><span class="line">                    System.out.println(<span class="string">&quot;每次读取一个字符:&quot;</span> + reader.read());</span><br><span class="line">                    <span class="keyword">int</span> data;<span class="comment">//可以不声明，这里data作为读取记录</span></span><br><span class="line">                    <span class="keyword">while</span> ((data = reader.read()) != -<span class="number">1</span>) &#123;</span><br><span class="line">                        System.out.print(data + <span class="string">&quot; &quot;</span>);</span><br><span class="line">                    &#125;</span><br><span class="line">                    System.out.println(<span class="string">&quot;读取结束！&quot;</span>);</span><br><span class="line">                    System.out.println(<span class="string">&quot;继续读取则为：&quot;</span> + reader.read());</span><br><span class="line">                    reader.close();</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="comment">//方法二：缓冲读取</span></span><br><span class="line">                &#123;</span><br><span class="line">                    reader = <span class="keyword">new</span> FileReader(file);</span><br><span class="line">                    <span class="keyword">char</span>[] chars = <span class="keyword">new</span> <span class="keyword">char</span>[<span class="number">17</span>];</span><br><span class="line">                    <span class="keyword">int</span> readIndex = reader.read(chars);</span><br><span class="line">                    System.out.println(<span class="string">&quot;read(char[])返回的是下标，下标为:&quot;</span> + readIndex);</span><br><span class="line">                    <span class="keyword">for</span> (<span class="keyword">char</span> aChar : chars) &#123;</span><br><span class="line">                        System.out.print(aChar + <span class="string">&quot; &quot;</span>);</span><br><span class="line">                    &#125;</span><br><span class="line">                    System.out.println(<span class="string">&quot;读取结束！&quot;</span>);</span><br><span class="line">                    System.out.println(<span class="string">&quot;在读取则为：&quot;</span> + reader.read());</span><br><span class="line">                    reader.close();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Test</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">FileO</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        String fileName = <span class="string">&quot;../JavaCode/src/files/outputStream.txt&quot;</span>;</span><br><span class="line">        File file = <span class="keyword">new</span> File(fileName);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="keyword">if</span> (!file.exists()) &#123;</span><br><span class="line">                <span class="keyword">if</span>(!file.createNewFile())&#123;</span><br><span class="line">                    <span class="keyword">throw</span> <span class="keyword">new</span> FilerException(<span class="string">&quot;文件创建失败！&quot;</span>);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="comment">//1、 OutputStream  --  FileOutputStream</span></span><br><span class="line">            &#123;</span><br><span class="line">                OutputStream os = <span class="keyword">new</span> FileOutputStream(file);</span><br><span class="line">                <span class="comment">//单个字节写入</span></span><br><span class="line">                os.write(<span class="number">48</span>);<span class="comment">// 0 的 byte 值等于 48</span></span><br><span class="line">                os.write(<span class="number">49</span>);<span class="comment">//这里写入的是字节，会将值转换为字节，再写入</span></span><br><span class="line">                os.write(<span class="number">50</span>);</span><br><span class="line">                os.write(<span class="string">&#x27;\n&#x27;</span>);</span><br><span class="line">                os.write(<span class="string">&#x27;0&#x27;</span>);</span><br><span class="line">                os.write(<span class="string">&#x27;1&#x27;</span>);</span><br><span class="line">                os.write(<span class="string">&#x27;2&#x27;</span>);</span><br><span class="line">                os.write(<span class="string">&#x27;\n&#x27;</span>);</span><br><span class="line">                <span class="comment">//利用缓存写入</span></span><br><span class="line">                <span class="keyword">byte</span>[] streamBytes = <span class="keyword">new</span> <span class="keyword">byte</span>[]&#123;<span class="string">&#x27;h&#x27;</span>, <span class="string">&#x27;e&#x27;</span>, <span class="string">&#x27;l&#x27;</span>, <span class="string">&#x27;l&#x27;</span>, <span class="string">&#x27;o&#x27;</span>&#125;;</span><br><span class="line">                os.write(streamBytes);</span><br><span class="line">                os.write(<span class="string">&#x27;\n&#x27;</span>);</span><br><span class="line">                <span class="comment">//写入bytes，从off位开始的len长度</span></span><br><span class="line">                os.write(streamBytes, <span class="number">1</span>, <span class="number">3</span>);</span><br><span class="line"></span><br><span class="line">                <span class="comment">//记得关闭</span></span><br><span class="line">                os.flush();</span><br><span class="line">                os.close();</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="comment">//2、 Writer  -- FileWriter,同上,第二个参数代表不覆盖写入</span></span><br><span class="line">            &#123;</span><br><span class="line">                Writer writer = <span class="keyword">new</span> FileWriter(file, <span class="keyword">true</span>);</span><br><span class="line">                <span class="comment">//单个字节写入</span></span><br><span class="line">                writer.write(<span class="number">48</span>);</span><br><span class="line">                writer.write(<span class="number">49</span>);</span><br><span class="line">                writer.write(<span class="number">50</span>);</span><br><span class="line">                writer.write(<span class="string">&#x27;\n&#x27;</span>);</span><br><span class="line"></span><br><span class="line">                <span class="comment">//利用缓存写入</span></span><br><span class="line">                <span class="keyword">char</span>[] writerBytes = <span class="keyword">new</span> <span class="keyword">char</span>[]&#123;<span class="string">&#x27;h&#x27;</span>, <span class="string">&#x27;e&#x27;</span>, <span class="string">&#x27;l&#x27;</span>, <span class="string">&#x27;l&#x27;</span>, <span class="string">&#x27;o&#x27;</span>&#125;;</span><br><span class="line">                writer.write(writerBytes);</span><br><span class="line"></span><br><span class="line">                <span class="comment">//前面如果没有写完，将强制写入</span></span><br><span class="line">                writer.flush();</span><br><span class="line">                <span class="comment">//如果不关闭，可能写入失败,所以必须关闭流</span></span><br><span class="line">                writer.close();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Test</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">FileCopy</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="comment">//这里利用读写，以及缓存读写来体验缓存的重要性</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">//普通的读写</span></span><br><span class="line">        String read = <span class="string">&quot;../JavaCode/src/files/outputStream.txt&quot;</span>;</span><br><span class="line">        String write = <span class="string">&quot;../JavaCode/src/files/temp2.txt&quot;</span>;</span><br><span class="line">        File fileOut = <span class="keyword">new</span> File(read);</span><br><span class="line">        File fileIn = <span class="keyword">new</span> File(write);</span><br><span class="line">        <span class="comment">//Reader,Writer</span></span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="keyword">if</span> (!fileOut.exists()) &#123;</span><br><span class="line">                <span class="keyword">if</span>(!fileOut.createNewFile())&#123;</span><br><span class="line">                    <span class="keyword">throw</span> <span class="keyword">new</span> FilerException(<span class="string">&quot;文件创建失败！&quot;</span>);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (!fileIn.exists()) &#123;</span><br><span class="line">                <span class="keyword">if</span>(!fileIn.createNewFile())&#123;</span><br><span class="line">                    <span class="keyword">throw</span> <span class="keyword">new</span> FilerException(<span class="string">&quot;文件创建失败！&quot;</span>);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            Reader reader;</span><br><span class="line">            Writer writer;</span><br><span class="line">            <span class="comment">//在这里有一点需要注意，</span></span><br><span class="line">            <span class="comment">// 当文件被一对一复制时（即读取一个字节复制一个字节），文件是多大，复制出来的就是多大，</span></span><br><span class="line">            <span class="comment">// 但是当文件被一对多复制时（即使用手动缓冲复制），文件可能会被扩容，且文件的所占容量是缓冲区的整数倍</span></span><br><span class="line">            &#123;</span><br><span class="line">                reader = <span class="keyword">new</span> FileReader(fileOut);</span><br><span class="line">                writer = <span class="keyword">new</span> FileWriter(fileIn);</span><br><span class="line">                System.out.print(<span class="string">&quot;读取一个字节，写入一个字节用时：&quot;</span>);</span><br><span class="line">                <span class="keyword">int</span> data;</span><br><span class="line">                <span class="keyword">long</span> start = System.currentTimeMillis();</span><br><span class="line">                <span class="keyword">while</span> ((data = reader.read()) != -<span class="number">1</span>) &#123;</span><br><span class="line">                    writer.write(data);</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="comment">//记得关闭</span></span><br><span class="line">                reader.close();</span><br><span class="line">                writer.flush();</span><br><span class="line">                writer.close();</span><br><span class="line">                <span class="keyword">long</span> end = System.currentTimeMillis();</span><br><span class="line">                System.out.println(end - start + <span class="string">&quot; ms&quot;</span>);</span><br><span class="line">            &#125;</span><br><span class="line">            &#123;</span><br><span class="line">                reader = <span class="keyword">new</span> FileReader(fileOut);</span><br><span class="line">                writer = <span class="keyword">new</span> FileWriter(fileIn);</span><br><span class="line">                System.out.print(<span class="string">&quot;缓冲读取用时:&quot;</span>);</span><br><span class="line">                <span class="keyword">char</span>[] buffer = <span class="keyword">new</span> <span class="keyword">char</span>[<span class="number">1024</span>];<span class="comment">// 1KB，速度提升了十倍以上，这里并不是缓冲越大越好，符合需要才是最好的</span></span><br><span class="line">                <span class="keyword">long</span> start = System.currentTimeMillis();</span><br><span class="line">                <span class="keyword">while</span> (reader.read(buffer) != -<span class="number">1</span>)&#123;</span><br><span class="line">                    writer.write(buffer);</span><br><span class="line">                &#125;</span><br><span class="line">                </span><br><span class="line">                <span class="comment">//记得关闭</span></span><br><span class="line">                reader.close();</span><br><span class="line">                writer.flush();</span><br><span class="line">                writer.close();</span><br><span class="line">                <span class="keyword">long</span> end = System.currentTimeMillis();</span><br><span class="line">                System.out.println(end - start + <span class="string">&quot; ms&quot;</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="BIO"><a href="#BIO" class="headerlink" title="BIO"></a>BIO</h3><blockquote>
<p>Blocking-IO，同步阻塞IO，应用程序发起read()请求后，会一直阻塞，直到在内核把数据拷贝到用户空间。</p>
</blockquote>
<p><img src="https://masuo-github-image.oss-cn-beijing.aliyuncs.com/image/20211221170413.webp" alt="图源：《深入拆解Tomcat &amp; Jetty》"> </p>
<p>示例：</p>
<p>我们模拟客户端发起read()请求，服务端接收read()请求，并将读取到的数据返回。</p>
<p>这里服务端（Server）要先启动，因为他是提供服务的。</p>
<p><strong>Client.java</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> JavaCore.MyIO.BIO;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.junit.Test;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">import</span> java.io.OutputStream;</span><br><span class="line"><span class="keyword">import</span> java.io.PrintStream;</span><br><span class="line"><span class="keyword">import</span> java.net.Socket;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> masuo</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@data</span> 2021/12/15 13:19</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Description</span> 客户端，</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Client</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Test</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">test1</span><span class="params">()</span></span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="comment">// 1、 客户端需要发送请求，发送请求之前需要先建立请求</span></span><br><span class="line">            Socket socket = <span class="keyword">new</span> Socket(<span class="string">&quot;127.0.0.1&quot;</span>,<span class="number">12000</span>);</span><br><span class="line">            <span class="comment">// 2、 建立请求之后，需要获取待发送数据,从socket中获取一个字节输出流</span></span><br><span class="line">            OutputStream os = socket.getOutputStream();</span><br><span class="line">            <span class="comment">// 3、 需要通过socket发送数据，需要将带发送数据包装成服务端想要的数据</span></span><br><span class="line">            PrintStream ps = <span class="keyword">new</span> PrintStream(os);</span><br><span class="line">            ps.print(<span class="string">&quot;这是带发送数据的第一行，不带换行即代表这一行信息还未发送结束，&quot;</span>);</span><br><span class="line">            ps.println(<span class="string">&quot;带换行即代表发送结束！&quot;</span>);</span><br><span class="line">            <span class="comment">//</span></span><br><span class="line">            ps.flush();</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>Server.java</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> JavaCore.MyIO.BIO;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.junit.Test;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.*;</span><br><span class="line"><span class="keyword">import</span> java.net.ServerSocket;</span><br><span class="line"><span class="keyword">import</span> java.net.Socket;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> masuo</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@data</span> 2021/12/15 13:19</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@Description</span> BIO服务端，BIO，同步且阻塞</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Server</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//服务端启动，</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">//BIO中，服务端会一直等待客户端发送消息，如果客户端没有进行发送消息，服务端将一直处于阻塞的状态</span></span><br><span class="line">    <span class="comment">// 同时，如果服务端是按照行获取消息的，这意味着客户端也必须按照行进行发送数据，否则服务端将一直处于等待状态，即阻塞状态</span></span><br><span class="line">    <span class="meta">@Test</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">test1</span><span class="params">()</span></span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;服务端启动&quot;</span>);</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="comment">// 1、 定义一个Server Socket对象进行服务端端口的注册</span></span><br><span class="line">            ServerSocket ss = <span class="keyword">new</span> ServerSocket(<span class="number">12000</span>);</span><br><span class="line">            <span class="comment">// 2、 监听客户端的socket连接请求</span></span><br><span class="line">            Socket socket = ss.accept();</span><br><span class="line">            <span class="comment">// 3、 从socket管道中得到一个字节输入流对象，</span></span><br><span class="line">            <span class="comment">// 注意这里，发送方怎么发，接收方就要怎么接</span></span><br><span class="line">            InputStream is = socket.getInputStream();</span><br><span class="line">            <span class="comment">//这里对请求进行转换</span></span><br><span class="line">            <span class="comment">//BufferedInputStream bis = new BufferedInputStream(is);</span></span><br><span class="line">            BufferedReader br = <span class="keyword">new</span> BufferedReader(<span class="keyword">new</span> InputStreamReader(is));</span><br><span class="line">            String msg;</span><br><span class="line">            <span class="keyword">if</span>((msg = br.readLine()) != <span class="keyword">null</span>)&#123;</span><br><span class="line">                System.out.println(msg);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="NIO"><a href="#NIO" class="headerlink" title="NIO"></a>NIO</h3><h3 id="AIO"><a href="#AIO" class="headerlink" title="AIO"></a>AIO</h3><hr>
<h2 id="锁"><a href="#锁" class="headerlink" title="锁"></a>锁</h2><blockquote>
<p>Java提供了种类丰富的锁，每种锁因其特性不同，在适当的场景下能展现出非常高的效率。</p>
<p>锁大致分为以下几种：自旋锁、阻塞锁、可重入锁、悲观锁、乐观锁、读写锁、偏向所、轻量级锁、重量级锁、锁膨胀、对象锁、类锁、页锁、行锁、表锁、</p>
<ul>
<li>乐观锁</li>
<li>悲观锁</li>
</ul>
</blockquote>
<h3 id="公平锁"><a href="#公平锁" class="headerlink" title="公平锁"></a>公平锁</h3><blockquote>
<p>乐观锁指的是线程之间对资源的抢占是有序的，大家都会排队。</p>
<p>所以乐观锁在尝试获取锁时，会申请锁（acquire），如果锁空闲，则直接获取锁；如果锁被占有，那么则去排队。</p>
</blockquote>
<p>代码如下（序号为执行流程，如有重复序号，则为多种情况）：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">final</span> <span class="class"><span class="keyword">class</span> <span class="title">FairSync</span> <span class="keyword">extends</span> <span class="title">Sync</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">long</span> serialVersionUID = -<span class="number">3000897897090466540L</span>;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">final</span> <span class="keyword">void</span> <span class="title">lock</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="comment">// 1.获取锁</span></span><br><span class="line">        acquire(<span class="number">1</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//acquire方法的实现</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">void</span> <span class="title">acquire</span><span class="params">(<span class="keyword">int</span> arg)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (!tryAcquire(arg)<span class="comment">//2.尝试获取锁，如果获取到了锁，那么直接返回，不再执行以下代码，否则继续执行</span></span><br><span class="line">        &amp;&amp; acquireQueued(addWaiter(Node.EXCLUSIVE), arg))<span class="comment">//6.没有获取到锁，则以独占模式入队</span></span><br><span class="line">        selfInterrupt();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//tryAcquire方法的实现</span></span><br><span class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">final</span> <span class="keyword">boolean</span> <span class="title">tryAcquire</span><span class="params">(<span class="keyword">int</span> acquires)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">final</span> Thread current = Thread.currentThread();<span class="comment">//3.获取当前线程</span></span><br><span class="line">    <span class="keyword">int</span> c = getState();<span class="comment">//4.获取锁状态</span></span><br><span class="line">    <span class="keyword">if</span> (c == <span class="number">0</span>) &#123;</span><br><span class="line">        <span class="comment">//5.如果锁空闲</span></span><br><span class="line">        <span class="keyword">if</span> (!hasQueuedPredecessors() &amp;&amp; <span class="comment">//5.1.先判断队列中是否有正在排队的线程</span></span><br><span class="line">            compareAndSetState(<span class="number">0</span>, acquires)) &#123; <span class="comment">//5.2.前面没有线程则直接获取锁（CAS原子操作）</span></span><br><span class="line">            setExclusiveOwnerThread(current); <span class="comment">//5.3.设置独占线程</span></span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">else</span> <span class="keyword">if</span> (current == getExclusiveOwnerThread()) &#123;</span><br><span class="line">        <span class="comment">//5.如果锁非空闲，</span></span><br><span class="line">        <span class="comment">//5.1此时需要判断占有锁的线程是不是当前线程，如果是当前线程，那么可以重复获取锁，即可重入锁</span></span><br><span class="line">        <span class="keyword">int</span> nextc = c + acquires;</span><br><span class="line">        <span class="keyword">if</span> (nextc &lt; <span class="number">0</span>)</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> Error(<span class="string">&quot;Maximum lock count exceeded&quot;</span>);</span><br><span class="line">        setState(nextc);<span class="comment">//5.2.更新锁状态</span></span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//5.以上都不符合则返回失败</span></span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//addWaiter方法的实现</span></span><br><span class="line"><span class="function"><span class="keyword">private</span> Node <span class="title">addWaiter</span><span class="params">(Node mode)</span> </span>&#123;</span><br><span class="line">    <span class="comment">//7.声明待入队的节点，注意，参数是mode，代表锁的模式</span></span><br><span class="line">    Node node = <span class="keyword">new</span> Node(Thread.currentThread(), mode);</span><br><span class="line">    <span class="comment">// Try the fast path of enq; backup to full enq on failure</span></span><br><span class="line">    Node pred = tail;</span><br><span class="line">    <span class="keyword">if</span> (pred != <span class="keyword">null</span>) &#123;</span><br><span class="line">        node.prev = pred;</span><br><span class="line">        <span class="keyword">if</span> (compareAndSetTail(pred, node)) &#123;</span><br><span class="line">            pred.next = node;</span><br><span class="line">            <span class="keyword">return</span> node;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    enq(node);</span><br><span class="line">    <span class="keyword">return</span> node;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<blockquote>
<p>乐观锁的实现又分以下几种：</p>
<ul>
<li>自旋锁</li>
</ul>
</blockquote>
<h3 id="非公平锁"><a href="#非公平锁" class="headerlink" title="非公平锁"></a>非公平锁</h3><blockquote>
<p>悲观锁指的是在县城需要获取锁的时候，直接获取锁（CAS），成功则设置当前线程为独占线程；如果获取失败，则再次尝试获取锁，获取失败则入队（CAS失败后的流程与乐观锁的流程是一致的）。</p>
</blockquote>
<h4 id="加锁"><a href="#加锁" class="headerlink" title="加锁"></a>加锁</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//非公平锁的加锁过程</span></span><br><span class="line"><span class="function"><span class="keyword">final</span> <span class="keyword">void</span> <span class="title">lock</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (compareAndSetState(<span class="number">0</span>, <span class="number">1</span>))<span class="comment">//1.直接获取锁（CAS）</span></span><br><span class="line">        setExclusiveOwnerThread(Thread.currentThread());<span class="comment">//2.成功则设置独占线程</span></span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">        acquire(<span class="number">1</span>);<span class="comment">//3.失败则尝试获取锁，</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//acquire方法，与乐观锁一致</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">void</span> <span class="title">acquire</span><span class="params">(<span class="keyword">int</span> arg)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (!tryAcquire(arg) &amp;&amp;<span class="comment">//4.尝试获取锁</span></span><br><span class="line">        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))<span class="comment">//7.第二次获取锁失败才会入队</span></span><br><span class="line">        selfInterrupt();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//非公平锁的tryAcquire方法</span></span><br><span class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">final</span> <span class="keyword">boolean</span> <span class="title">tryAcquire</span><span class="params">(<span class="keyword">int</span> acquires)</span> </span>&#123;</span><br><span class="line">    <span class="comment">//5.非公平锁的尝试获取锁方法</span></span><br><span class="line">    <span class="keyword">return</span> nonfairTryAcquire(acquires);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//nonfairTryAcquire方法</span></span><br><span class="line"><span class="function"><span class="keyword">final</span> <span class="keyword">boolean</span> <span class="title">nonfairTryAcquire</span><span class="params">(<span class="keyword">int</span> acquires)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">final</span> Thread current = Thread.currentThread();</span><br><span class="line">    <span class="keyword">int</span> c = getState();</span><br><span class="line">    <span class="keyword">if</span> (c == <span class="number">0</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (compareAndSetState(<span class="number">0</span>, acquires)) &#123;<span class="comment">//6.这里是非公平锁与公平锁不一致的地方，非公平锁直接获取锁，在此时不会入队</span></span><br><span class="line">            setExclusiveOwnerThread(current);</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">else</span> <span class="keyword">if</span> (current == getExclusiveOwnerThread()) &#123;</span><br><span class="line">        <span class="keyword">int</span> nextc = c + acquires;</span><br><span class="line">        <span class="keyword">if</span> (nextc &lt; <span class="number">0</span>) <span class="comment">// overflow</span></span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> Error(<span class="string">&quot;Maximum lock count exceeded&quot;</span>);</span><br><span class="line">        setState(nextc);</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="入队"><a href="#入队" class="headerlink" title="入队"></a>入队</h4><blockquote>
<p>在对上面的加锁有一定了解之后，我们来看一下入队是如何实现的。</p>
<p>入队方法是<code>acquireQueued(addWaiter(Node.EXCLUSIVE), arg)</code>，先执行<code>addWaiter</code>方法。</p>
<p>需要注意的是，虽然此时有一个线程正持有资源锁，但是入队操作对持有资源锁的线程并不影响。</p>
</blockquote>
<p>在AQS中，队列是使用链表来实现的，链表的节点结构如下</p>
<h5 id="Node"><a href="#Node" class="headerlink" title="Node"></a>Node</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">final</span> <span class="class"><span class="keyword">class</span> <span class="title">Node</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">final</span> Node SHARED = <span class="keyword">new</span> Node();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">final</span> Node EXCLUSIVE = <span class="keyword">null</span>;</span><br><span class="line">	<span class="comment">//cancel</span></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> CANCELLED =  <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> SIGNAL    = -<span class="number">1</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> CONDITION = -<span class="number">2</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> PROPAGATE = -<span class="number">3</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">volatile</span> <span class="keyword">int</span> waitStatus;</span><br><span class="line">	<span class="comment">//前置节点</span></span><br><span class="line">    <span class="keyword">volatile</span> Node prev;</span><br><span class="line">	<span class="comment">//后置节点</span></span><br><span class="line">    <span class="keyword">volatile</span> Node next;</span><br><span class="line">	<span class="comment">//节点线程</span></span><br><span class="line">    <span class="keyword">volatile</span> Thread thread;</span><br><span class="line"></span><br><span class="line">    Node nextWaiter;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">final</span> <span class="keyword">boolean</span> <span class="title">isShared</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> nextWaiter == SHARED;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">final</span> Node <span class="title">predecessor</span><span class="params">()</span> <span class="keyword">throws</span> NullPointerException </span>&#123;</span><br><span class="line">        Node p = prev;</span><br><span class="line">        <span class="keyword">if</span> (p == <span class="keyword">null</span>)</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> NullPointerException();</span><br><span class="line">        <span class="keyword">else</span></span><br><span class="line">            <span class="keyword">return</span> p;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    Node() &#123;    <span class="comment">// Used to establish initial head or SHARED marker</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//此方法即入队时调用的生产节点的方法</span></span><br><span class="line">    Node(Thread thread, Node mode) &#123;     <span class="comment">// Used by addWaiter</span></span><br><span class="line">        <span class="comment">//下一个等待者为xx模式</span></span><br><span class="line">        <span class="keyword">this</span>.nextWaiter = mode;</span><br><span class="line">        <span class="keyword">this</span>.thread = thread;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    Node(Thread thread, <span class="keyword">int</span> waitStatus) &#123; <span class="comment">// Used by Condition</span></span><br><span class="line">        <span class="keyword">this</span>.waitStatus = waitStatus;</span><br><span class="line">        <span class="keyword">this</span>.thread = thread;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h5 id="addWaiter"><a href="#addWaiter" class="headerlink" title="addWaiter"></a>addWaiter</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//addWaiter方法，参数mode为 Node.EXCLUSIVE，表示为独占模式</span></span><br><span class="line"><span class="function"><span class="keyword">private</span> Node <span class="title">addWaiter</span><span class="params">(Node mode)</span> </span>&#123;</span><br><span class="line">    <span class="comment">//声明当前线程为新节点，Node</span></span><br><span class="line">    Node node = <span class="keyword">new</span> Node(Thread.currentThread(), mode);</span><br><span class="line">    <span class="comment">// Try the fast path of enq; backup to full enq on failure</span></span><br><span class="line">    Node pred = tail;</span><br><span class="line">    <span class="comment">//第一次进入addWaiter方法时，tail为null，所以我们直接进入enq方法</span></span><br><span class="line">    <span class="keyword">if</span> (pred != <span class="keyword">null</span>) &#123;</span><br><span class="line">        node.prev = pred;</span><br><span class="line">        <span class="keyword">if</span> (compareAndSetTail(pred, node)) &#123;</span><br><span class="line">            pred.next = node;</span><br><span class="line">            <span class="keyword">return</span> node;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    enq(node);</span><br><span class="line">    <span class="keyword">return</span> node;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<h5 id="enq"><a href="#enq" class="headerlink" title="enq"></a>enq</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> Node <span class="title">enq</span><span class="params">(<span class="keyword">final</span> Node node)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">for</span> (;;) &#123;<span class="comment">//死循环</span></span><br><span class="line">        Node t = tail;<span class="comment">//第一次循环时，tail为null</span></span><br><span class="line">        <span class="keyword">if</span> (t == <span class="keyword">null</span>) &#123; <span class="comment">// Must initialize</span></span><br><span class="line">            <span class="keyword">if</span> (compareAndSetHead(<span class="keyword">new</span> Node()))<span class="comment">//设置head节点</span></span><br><span class="line">                tail = head;<span class="comment">//设置tail节点</span></span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="comment">//第二次循环</span></span><br><span class="line">            node.prev = t;<span class="comment">//设置node的前置节点为t，即tail</span></span><br><span class="line">            <span class="keyword">if</span> (compareAndSetTail(t, node)) &#123;<span class="comment">//此操作表示如果t为tail，则将node设置为新的tail</span></span><br><span class="line">                <span class="comment">//此时t指向</span></span><br><span class="line">                t.next = node;</span><br><span class="line">                <span class="keyword">return</span> t;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//  compareAndSetHead CAS</span></span><br><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">boolean</span> <span class="title">compareAndSetHead</span><span class="params">(Node update)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> unsafe.compareAndSwapObject(<span class="keyword">this</span>, headOffset, <span class="keyword">null</span>, update);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="阻塞"><a href="#阻塞" class="headerlink" title="阻塞"></a>阻塞</h4><blockquote>
<p>在入队完成之后，此线程不能继续执行，那么我们就需要阻塞该线程。</p>
<p>在AQS中阻塞线程的方法就是通过自旋（自循环）来阻塞线程，同时还需要给出线程跳出循环的条件，即成功获取到锁就跳出循环，结束阻塞。</p>
</blockquote>
<h5 id="acquireQueued"><a href="#acquireQueued" class="headerlink" title="acquireQueued"></a>acquireQueued</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//acquireQueued方法</span></span><br><span class="line"><span class="function"><span class="keyword">final</span> <span class="keyword">boolean</span> <span class="title">acquireQueued</span><span class="params">(<span class="keyword">final</span> Node node, <span class="keyword">int</span> arg)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">boolean</span> failed = <span class="keyword">true</span>;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="keyword">boolean</span> interrupted = <span class="keyword">false</span>;</span><br><span class="line">        <span class="keyword">for</span> (;;) &#123;<span class="comment">//自循环</span></span><br><span class="line">            <span class="keyword">final</span> Node p = node.predecessor();<span class="comment">//获取前置节点</span></span><br><span class="line">            <span class="comment">//第一个if判断的是该线程是否为头节点，且是否成功获取到锁</span></span><br><span class="line">            <span class="keyword">if</span> (p == head &amp;&amp; tryAcquire(arg)) &#123;</span><br><span class="line">                <span class="comment">//如果成功获取到锁，则将node设置为头节点，因为p为node的前置节点</span></span><br><span class="line">                setHead(node);</span><br><span class="line">                <span class="comment">//此处，因为p即将跳出循环，我们不需要后置节点，后置节点存储在node对象里，所以将其设置为空，防止内存泄露</span></span><br><span class="line">                p.next = <span class="keyword">null</span>; <span class="comment">// help GC</span></span><br><span class="line">                failed = <span class="keyword">false</span>;</span><br><span class="line">                <span class="keyword">return</span> interrupted;<span class="comment">//不在阻塞</span></span><br><span class="line">            &#125;</span><br><span class="line">            <span class="comment">//第二个if表示，此线程获取锁失败，则应该继续阻塞</span></span><br><span class="line">            <span class="keyword">if</span> (shouldParkAfterFailedAcquire(p, node) <span class="comment">//表示线程在获取锁失败后是否应该阻塞</span></span><br><span class="line">                &amp;&amp;</span><br><span class="line">                parkAndCheckInterrupt())<span class="comment">//阻塞并且检查阻塞状态，此方法为实际阻塞方法</span></span><br><span class="line">                interrupted = <span class="keyword">true</span>;<span class="comment">//继续阻塞</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (failed)</span><br><span class="line">            cancelAcquire(node);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h5 id="shouldParkAfterFailedAcquire"><a href="#shouldParkAfterFailedAcquire" class="headerlink" title="shouldParkAfterFailedAcquire"></a>shouldParkAfterFailedAcquire</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//给线程找到正确的阻塞位置</span></span><br><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">boolean</span> <span class="title">shouldParkAfterFailedAcquire</span><span class="params">(Node pred, Node node)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">int</span> ws = pred.waitStatus;</span><br><span class="line">    <span class="keyword">if</span> (ws == Node.SIGNAL)<span class="comment">//-1</span></span><br><span class="line">       </span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">    <span class="keyword">if</span> (ws &gt; <span class="number">0</span>) &#123;</span><br><span class="line">        <span class="comment">//表示前一节点已放弃，则跳过此节点</span></span><br><span class="line">        <span class="keyword">do</span> &#123;</span><br><span class="line">            node.prev = pred = pred.prev;</span><br><span class="line">        &#125; <span class="keyword">while</span> (pred.waitStatus &gt; <span class="number">0</span>);</span><br><span class="line">        pred.next = node;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        </span><br><span class="line">        compareAndSetWaitStatus(pred, ws, Node.SIGNAL);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h5 id="parkAndCheckInterrupt"><a href="#parkAndCheckInterrupt" class="headerlink" title="parkAndCheckInterrupt"></a>parkAndCheckInterrupt</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">boolean</span> <span class="title">parkAndCheckInterrupt</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="comment">//调用LockSupport的park方法阻塞线程</span></span><br><span class="line">    LockSupport.park(<span class="keyword">this</span>);<span class="comment">//在此处，线程被阻塞，不再执行</span></span><br><span class="line">    <span class="keyword">return</span> Thread.interrupted();<span class="comment">//线程被唤起之后执行的代码</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="释放"><a href="#释放" class="headerlink" title="释放"></a>释放</h4><blockquote>
<p>unLock（）方法</p>
</blockquote>
<hr>
<h2 id="JVM"><a href="#JVM" class="headerlink" title="JVM"></a>JVM</h2><p>首先，什么是JVM(Java Virtual Machine,java虚拟机)，类似于一个平台，但不是Windows，Linux等这样的操作系统平台，而是介于代码与操作系统之间的一层平台，负责将java代码编译成下层平台能读懂的指令</p>
<p>参考自：<a target="_blank" rel="noopener" href="https://zhuanlan.zhihu.com/p/34426768">https://zhuanlan.zhihu.com/p/34426768</a> 。</p>
<p>至于你是先学习类的加载机制还是先学习JVM的内存结构看个人掌握情况，从你写好的代码到程序运行期间发生了什么？流程是什么？</p>
<p>目前的掌握是：Demo.java(自建)—&gt;Demo. class—&gt;</p>
<h3 id="Java类的加载机制"><a href="#Java类的加载机制" class="headerlink" title="Java类的加载机制"></a>Java类的加载机制</h3><p><img src="https://pic3.zhimg.com/v2-dfc3b65b983a82e84420e1335a507e2a_r.jpg" alt="preview"></p>

      
    </div><!-- .entry-content -->

    <footer class="entry-meta">
    <a href="/2021/08/01/java/">
    <time datetime="2021-08-01T00:00:00.000Z" class="entry-date">
        2021-08-01
    </time>
</a>
    
    
    </footer>
</article>


    
<nav class="nav-single">
    <h3 class="assistive-text">文章导航</h3>
    
        <span class="nav-previous"><a href="/2021/08/10/Design%20Model/" rel="prev"><span class="meta-nav">←</span> Design Model</a></span>
    
    
        <span class="nav-next"><a href="/2021/07/28/Computer/" rel="next">计算机 <span class="meta-nav">→</span></a></span>
    
</nav><!-- .nav-single -->






<section id="comments">
  <!-- 多说评论框 start -->
  <div class="ds-thread" data-thread-key="post-java" data-title="Java" data-url="https://masuo777.github.io/2021/08/01/java/"></div>
  <!-- 多说评论框 end -->
  <!-- 多说公共JS代码 start (一个网页只需插入一次) -->
  <script type="text/javascript">
  var duoshuoQuery = {short_name:'ms'};
    (function() {
	  var ds = document.createElement('script');
	  ds.type = 'text/javascript';ds.async = true;
	  ds.src = (document.location.protocol == 'https:' ? 'https:' : 'http:') + '//static.duoshuo.com/embed.js';
	  ds.charset = 'UTF-8';
	  (document.getElementsByTagName('head')[0]
	   || document.getElementsByTagName('body')[0]).appendChild(ds);
    })();
  </script>
  <!-- 多说公共JS代码 end -->
</section>


</div></div>
        <div id="secondary" class="widget-area" role="complementary">
  
    <aside class="widget">
    <h3 class="widget-title">CONTACT ME</h3>
    <div class="widget-content">
      <p>邮箱：masuo0.0@foxmail.com</p>
      <p>QQ：2919029885</p>
      <a target="_blank" rel="noopener" href="https://www.cnblogs.com/msdog/">博客园</a>
      </br>
      <img src="https://masuo-github-image.oss-cn-beijing.aliyuncs.com/image/20210701223301.jpg" height="250px"/>
      
    </div>
</aside>
  
    <aside class="widget">
    <h3 class="widget-title">赞助我</h3>
    <div class="widget-content">
      <img src='/css/images/alipay.png' style='width:100%;' />
    </div>
</aside>
  
    <aside class="widget">
    <h3 class="widget-title">公众号</h3>
    <div class="widget-content">
      <p>暂时没有，待我代码行数100000，我可能才有这个资格吧。</p>
      <p></p>
    </div>
</aside>
  
</div>
      </div>
      <footer id="colophon" role="contentinfo">
    <p>&copy; 2022 John Doe; All rights reserved.</p>
    <p>Powered by <a href="http://hexo.io/" target="_blank">Hexo</a></p>
</footer>
    <script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"1","bdMiniList":false,"bdPic":"","bdStyle":"2","bdSize":"16"},"share":{}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];</script>

<script src="/js/jquery-2.0.3.min.js"></script>


  
<link rel="stylesheet" href="/fancybox/jquery.fancybox.css">

  
<script src="/fancybox/jquery.fancybox.pack.js"></script>




<script src="/js/script.js"></script>


<script src="/js/navigation.js"></script>

<div id="bg"></div>

  </div>
</body>
</html>